Data Structures In JavaScript
Leetcode Problems
Data Structures In JavaScript

Problem:

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example
1
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
2
Output: 7 -> 0 -> 8
3
Explanation: 342 + 465 = 807.
Copied!

Solution:

Mind the last carry.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} l1
10
* @param {ListNode} l2
11
* @return {ListNode}
12
*/
13
let addTwoNumbers = function(l1, l2) {
14
const prehead = new ListNode()
15
let p = prehead
16
let carry = 0
17
18
for (let p1 = l1, p2 = l2: p1 || p2 || carry > 0; p = p.next) {
19
let sum = carry
20
if (p1) {
21
sum += p1.val
22
p1 = p1.next
23
}
24
if (p2) {
25
sum += p2.val
26
p2 = p2.next
27
}
28
carry = sum / 10 | 0
29
p.next = new ListNode(sum % 10)
30
}
31
32
return prehead.next
33
};
Copied!
Template generated via Leetmark.

Problem:

There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Example 1:
1
nums1 = [1, 3]
2
nums2 = [2]
3
4
The median is 2.0
Copied!
Example 2:
1
nums1 = [1, 2]
2
nums2 = [3, 4]
3
4
The median is (2 + 3)/2 = 2.5
Copied!

Solution:

O(log (m+n)) means half of the sequence is ruled out on each loop. So obviously we need binary search.
To do it on two sorted arrays, we need a formula to guide division.
Let nums3 be the sorted array combining all the items in nums1 and nums2.
If nums2[j-1] <= nums1[i] <= nums2[j], then we know nums1[i] is at num3[i+j]. Same goes nums1[i-1] <= nums2[j] <= nums1[i].
Let k be ⌊(m+n-1)/2⌋. We need to find nums3[k] (and also nums3[k+1] if m+n is even).
Let i + j = k, if we find nums2[j-1] <= nums1[i] <= nums2[j] or nums1[i-1] <= nums2[j] <= nums1[i], then we got k.
Otherwise, if nums1[i] <= nums2[j] then we know nums1[i] < nums2[j-1] (because we did not find k).
  • There are i items before nums1[i], and j-1 items brefor nums2[j-1], which means nums1[0...i] are before nums3[i+j-1]. So we now know nums1[0...i] < nums3[k]. They can be safely discarded.
  • We Also have nums1[i] < nums2[j], which means nums2[j...n) are after nums3[i+j]. So nums2[j...n) > nums3[k].
Same goes nums1[i-1] <= nums2[j] <= nums1[i].
1
/**
2
* @param {number[]} nums1
3
* @param {number[]} nums2
4
* @return {number}
5
*/
6
let findMedianSortedArrays = function (nums1, nums2) {
7
const mid = (nums1.length + nums2.length - 1) / 2 | 0
8
9
if ((nums1.length + nums2.length) % 2 === 0) {
10
return (_find(nums1, nums2, mid) + _find(nums1, nums2, mid + 1)) / 2
11
}
12
13
return _find(nums1, nums2, mid)
14
}
15
16
17
function _find (nums1, nums2, k) {
18
if (nums1.length > nums2.length) {
19
// So that the `i` below is always smalller than k,
20
// which makes `j` always non-negative
21
[nums1, nums2] = [nums2, nums1]
22
}
23
let s1 = 0
24
let s2 = 0
25
let e1 = nums1.length
26
let e2 = nums2.length
27
28
while (s1 < e1 || s2 < e2) {
29
const i = s1 + ((e1 - s1) / 2 | 0)
30
const j = k - i
31
const ni = i >= e1 ? Infinity : nums1[i]
32
const nj = j >= e2 ? Infinity : nums2[j]
33
const ni_1 = i <= 0 ? -Infinity : nums1[i-1]
34
const nj_1 = j <= 0 ? -Infinity : nums2[j-1]
35
36
if (nj_1 <= ni && ni <= nj) {
37
return ni
38
}
39
40
if (ni_1 <= nj && nj <= ni) {
41
return nj
42
}
43
44
if (ni <= nj) {
45
s1 = i + 1
46
e2 = j
47
} else {
48
s2 = j + 1
49
e1 = i
50
}
51
}
52
};
Copied!
Template generated via Leetmark.

Problem:

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
1
P A H N
2
A P L S I I G
3
Y I R
Copied!
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
1
string convert(string s, int numRows);
Copied!
Example 1:
1
Input: s = "PAYPALISHIRING", numRows = 3
2
Output: "PAHNAPLSIIGYIR"
Copied!
Example 2:
1
Input: s = "PAYPALISHIRING", numRows = 4
2
Output: "PINALSIGYAHRPI"
3
Explanation:
4
5
P I N
6
A L S I G
7
Y A H R
8
P I
Copied!

Solution:

Squeeze the zigzag pattern horizontally to form a matrix. Now deal with the odd and even columns respectively.
For example let numRows be 5, if we list out the indecies:
1
row
2
1 00 08 16
3
2 01 07 09 15 17
4
3 02 06 10 14 18
5
4 03 05 11 13 19
6
5 04 12 20
Copied!
First calculate the matrix width:
1
pairs = floor( len(s) / (numRows + numRows - 2) )
2
width = pairs * 2 + ceil( (len(s) - pairs * (numRows + numRows - 2)) / numRows )
Copied!
We can easily make a observation that the direction of odd and even columns and different.
Let the first column be index 0 and let i be the current position at column col.
We need to count the items between matrix[row][col] and matrix[row][col+1], exclusive.
1
next_i = i + (numRows - row) + (numRows - row), if col is even && 1 < row < numRows
2
next_i = i + row - 2 + row, if col is odd && 1 < row < numRows
Copied!
If row == 1 or row == numRows, skip the odd columns.
1
next_i = i + numRows + (numRows - 2), if col is even && (row == 1 || row == numRows)
Copied!
1
/**
2
* @param {string} s
3
* @param {number} numRows
4
* @return {string}
5
*/
6
let convert = function(s, numRows) {
7
if (numRows <= 1) { return s }
8
9
const pairs = Math.floor(s.length / (numRows + numRows - 2))
10
const width = pairs * 2 + Math.ceil((s.length - pairs * (numRows + numRows - 2)) / numRows)
11
12
let result = ''
13
14
for (let row = 1; row <= numRows; row++) {
15
let i = row - 1
16
result += s[i] || ''
17
for (let col = 0; col < width; col++) {
18
if (row === 1 || row === numRows) {
19
if (col % 2 === 0) {
20
i += numRows + (numRows - 2)
21
} else {
22
continue
23
}
24
} else {
25
if (col % 2 === 0) {
26
i += (numRows - row) + (numRows - row)
27
} else {
28
i += row - 2 + row
29
}
30
}
31
result += s[i] || ''
32
}
33
}
34
35
return result
36
};
Copied!
Template generated via Leetmark.

Problem:

Given a 32-bit signed integer, reverse digits of an integer.
Example 1:
1
Input: 123
2
Output: 321
Copied!
Example 2:
1
Input: -123
2
Output: -321
Copied!
Example 3:
1
Input: 120
2
Output: 21
Copied!
Note: Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

Solution:

ONE
This is a JavaScript specific solution. It is esay to write but slow to run because it generates O(n) space. This could end up a huge array.
1
/**
2
* @param {number} x
3
* @return {number}
4
*/
5
let reverse = function(x) {
6
let n = Math.abs(x).toString().split('').reverse().join('')
7
if (n > 2147483647) { return 0 }
8
return (x < 0? -1: 1) * n
9
};
Copied!
TWO
Pure mathamatical solution.
1
/**
2
* @param {number} x
3
* @return {number}
4
*/
5
let reverse = function(x) {
6
let result = 0
7
while (x) {
8
result = result * 10 + x % 10
9
x = x / 10 | 0
10
}
11
return Math.abs(result) > 2147483647 ? 0 : result
12
};
Copied!
Template generated via Leetmark.

Problem:

Implement atoi which converts a string to an integer.
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned.
Note:
Only the space character ' ' is considered as whitespace character. Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. If the numerical value is out of the range of representable values, INT_MAX (231 − 1) or INT_MIN (−231) is returned.
Example 1:
1
Input: "42"
2
Output: 42
Copied!
Example 2:
1
Input: " -42"
2
Output: -42
3
Explanation: The first non-whitespace character is '-', which is the minus sign.
4
Then take as many numerical digits as possible, which gets 42.
Copied!
Example 3:
1
Input: "4193 with words"
2
Output: 4193
3
Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
Copied!
Example 4:
1
Input: "words and 987"
2
Output: 0
3
Explanation: The first non-whitespace character is 'w', which is not a numerical
4
digit or a +/- sign. Therefore no valid conversion could be performed.
Copied!
Example 5:
1
Input: "-91283472332"
2
Output: -2147483648
3
Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer.
4
Thefore INT_MIN (−231) is returned.
Copied!

Solution:

ONE
1
/**
2
* @param {string} str
3
* @return {number}
4
*/
5
let myAtoi = function (str) {
6
return Math.min(2147483647, Math.max(-2147483648, parseInt(str))) || 0
7
};
Copied!
TWO
Looks like Number() is faster than parseInt().
1
/**
2
* @param {string} str
3
* @return {number}
4
*/
5
let myAtoi = function (str) {
6
return Math.min(2147483647, Math.max(-2147483648, (/^ *[-+]?\d+/.exec(str) || [0])[0]))
7
};
Copied!
THREE
General solution.
1
/**
2
* @param {string} str
3
* @return {number}
4
*/
5
let myAtoi = function (str) {
6
let sign = 1
7
let i = 0
8
9
while (i < str.length) {
10
const cc = str.charCodeAt(i++)
11
if (cc === 45) { // -
12
sign = -1
13
break
14
} else if (cc === 43) { // +
15
break
16
} else if (cc >= 48 && cc <= 57) { // 0-9
17
i--
18
break
19
} else if (cc !== 32) { // space
20
return 0
21
}
22
}
23
24
let result = 0
25
while (i < str.length) {
26
const digit = str.charCodeAt(i++) - 48
27
if (digit < 0 || digit > 9) {
28
break
29
}
30
result = result * 10 + digit
31
}
32
33
return Math.min(2147483647, Math.max(-2147483648, result * sign))
34
};
Copied!
Template generated via Leetmark.

Problem:

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.
Example 1:
1
Input: 121
2
Output: true
Copied!
Example 2:
1
Input: -121
2
Output: false
3
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
Copied!
Example 3:
1
Input: 10
2
Output: false
3
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.
Copied!
Follow up:
Coud you solve it without converting the integer to a string?

Solution:

ONE
Easy to write but slow since it generates an array.
1
/**
2
* @param {number} x
3
* @return {boolean}
4
*/
5
let isPalindrome = function(x) {
6
return x == String(x).split('').reverse().join('')
7
};
Copied!
TWO
A bit faster.
1
/**
2
* @param {number} x
3
* @return {boolean}
4
*/
5
let isPalindrome = function(x) {
6
const s = String(x)
7
for (let i = 0, j = s.length -1; i < j; i++, j--) {
8
if (s[i] !== s[j]) {
9
return false
10
}
11
}
12
return true
13
};
Copied!
THREE
General solution. Combining 7. Reverse Integer.
1
/**
2
* @param {number} x
3
* @return {boolean}
4
*/
5
let isPalindrome = function(x) {
6
if (x < 0) { return false }
7
return x === reverse(x)
8
};
9
10
/**
11
* @param {number} x
12
* @return {number}
13
*/
14
function reverse (x) {
15
let result = 0
16
while (x) {
17
result = result * 10 + x % 10
18
x = x / 10 | 0
19
}
20
return result
21
};
Copied!
Template generated via Leetmark.

Problem:

Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'.
1
'.' Matches any single character.
2
'*' Matches zero or more of the preceding element.
Copied!
The matching should cover the entire input string (not partial).
Note:
s could be empty and contains only lowercase letters a-z. p could be empty and contains only lowercase letters a-z, and characters like . or *.
Example 1:
1
Input:
2
s = "aa"
3
p = "a"
4
Output: false
5
Explanation: "a" does not match the entire string "aa".
Copied!
Example 2:
1
Input:
2
s = "aa"
3
p = "a*"
4
Output: true
5
Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Copied!
Example 3:
1
Input:
2
s = "ab"
3
p = ".*"
4
Output: true
5
Explanation: ".*" means "zero or more (*) of any character (.)".
Copied!
Example 4:
1
Input:
2
s = "aab"
3
p = "c*a*b"
4
Output: true
5
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
Copied!
Example 5:
1
Input:
2
s = "mississippi"
3
p = "mis*is*p*."
4
Output: false
Copied!

Solution:

ONE
Cheating with real RegExp matching.
1
/**
2
* @param {string} s
3
* @param {string} p
4
* @return {boolean}
5
*/
6
let isMatch = function(s, p) {
7
if (p[0] === '*') { return false }
8
return new RegExp(`^${p} Data Structures In JavaScript - datastructures-in-python ).test(s)
9
};
Copied!
TWO
Let f(i, j) be the matching result of s[0...i) and p[0...j).
1
f(0, j) =
2
j == 0 || // empty
3
p[j-1] == '*' && f(i, j-2) // matches 0 time, which matches empty string
4
5
f(i, 0) = false // pattern must cover the entire input string
6
7
f(i, j) =
8
if p[j-1] == '.'
9
f(i-1, j-1)
10
else if p[j-1] == '*'
11
f(i, j-2) || // matches 0 time
12
f(i-1, j) && (s[i-1] == p[j-2] || p[j-2] == '.') // matches 1 or multiple times
13
else
14
f(i-1, j-1) && s[i-1] == p[j-1]
Copied!
1
/**
2
* @param {string} s
3
* @param {string} p
4
* @return {boolean}
5
*/
6
let isMatch = function(s, p) {
7
if (p[0] === '*') {
8
return false
9
}
10
11
const dp = [[true]]
12
13
for (let j = 2; j <= p.length; j++) {
14
dp[0][j] = p[j-1] === '*' && dp[0][j-2]
15
}
16
17
for (let i = 1; i <= s.length; i++) {
18
dp[i] = []
19
for (let j = 1; j <= p.length; j++) {
20
switch (p[j-1]) {
21
case '.':
22
dp[i][j] = dp[i-1][j-1]
23
break
24
case '*':
25
dp[i][j] = dp[i][j-2] ||
26
dp[i-1][j] && (p[j-2] === '.' || s[i-1] === p[j-2])
27
break
28
default:
29
dp[i][j] = dp[i-1][j-1] && s[i-1] === p[j-1]
30
}
31
}
32
}
33
34
return !!dp[s.length][p.length]
35
}
Copied!
Template generated via Leetmark.

Problem:

Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.

Solution:

Greedy Algorithm.
If we look at the simple brute force approach, where we choose one point at a time and calculate all the possible areas with other points on the right, it is easy to make a observation that we are narrowing down the horizontal distance.
Greedy Algorithm can help us skip some of the conditions. It is base on a fact that the area between two columns are determined by the shorter one.
Let's say we have pointer l and r at the begin and end of a distance, and the area is area(l, r), how should we narrow down the distance?
If height[l] < height[r], we know that the height of the area will never be greater than height[l] if we keep l. Now if we get rid of r, the area can only get smaller since the distance is shorter, and the height is at most height[l].
Here we conclude rule NO.1: Get rid of the smaller one.
What if height[l] == height[r]? It is safe to get rid of both. We do not need any of them to constrain the max height of the rest points.
1
/**
2
* @param {number[]} height
3
* @return {number}
4
*/
5
let maxArea = function (height) {
6
let max = 0
7
for (let l = 0, r = height.length - 1; l < r; l++, r--) {
8
max = Math.max(max, (r - l) * Math.min(height[l], height[r]))
9
if (height[l] < height[r]) {
10
r++
11
} else {
12
l--
13
}
14
}
15
return max
16
};
Copied!
Template generated via Leetmark.

Problem:

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
1
Symbol Value
2
I 1
3
V 5
4
X 10
5
L 50
6
C 100
7
D 500
8
M 1000
Copied!
For example, two is written as II in Roman numeral, just two one's added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:
  • I can be placed before V (5) and X (10) to make 4 and 9.
  • X can be placed before L (50) and C (100) to make 40 and 90.
  • C can be placed before D (500) and M (1000) to make 400 and 900.
Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.
Example 1:
1
Input: 3
2
Output: "III"
Copied!
Example 2:
1
Input: 4
2
Output: "IV"
Copied!
Example 3:
1
Input: 9
2
Output: "IX"
Copied!
Example 4:
1
Input: 58
2
Output: "LVIII"
3
Explanation: C = 100, L = 50, XXX = 30 and III = 3.
Copied!
Example 5:
1
Input: 1994
2
Output: "MCMXCIV"
3
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
Copied!

Solution:

Treat 4, 40, 400 and 9, 90, 900 specially.
1
/**
2
* @param {number} num
3
* @return {string}
4
*/
5
let intToRoman = function(num) {
6
const e = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ]
7
const s = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
8
9
let result = ''
10
for (let i = 0; num; i++) {
11
const d = e[i]
12
const v = s[i]
13
while (num >= d) {
14
num -= d
15
result += v
16
}
17
}
18
return result
19
};
Copied!
Template generated via Leetmark.

Problem:

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
1
Symbol Value
2
I 1
3
V 5
4
X 10
5
L 50
6
C 100
7
D 500
8
M 1000
Copied!
For example, two is written as II in Roman numeral, just two one's added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:
  • I can be placed before V (5) and X (10) to make 4 and 9.
  • X can be placed before L (50) and C (100) to make 40 and 90.
  • C can be placed before D (500) and M (1000) to make 400 and 900.
Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.
Example 1:
1
Input: "III"
2
Output: 3
Copied!
Example 2:
1
Input: "IV"
2
Output: 4
Copied!
Example 3:
1
Input: "IX"
2
Output: 9
Copied!
Example 4:
1
Input: "LVIII"
2
Output: 58
3
Explanation: C = 100, L = 50, XXX = 30 and III = 3.
Copied!
Example 5:
1
Input: "MCMXCIV"
2
Output: 1994
3
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
Copied!

Solution:

Normally we just add up the digits, except when the digit is greater than its left (e.g. IV). In that case we need to fallback and remove the last digit then combine the two as new digit. That is why we subtract the last digit twice.
1
/**
2
* @param {string} s
3
* @return {number}
4
*/
5
let romanToInt = function (s) {
6
const rdigit = {
7
I: 1,
8
V: 5,
9
X: 10,
10
L: 50,
11
C: 100,
12
D: 500,
13
M: 1000,
14
}
15
16
let result = 0
17
for (let i = 0, lastDigit = Infinity; i < s.length; i++) {
18
let digit = rdigit[s[i]]
19
result += digit <= lastDigit ? digit : digit - lastDigit * 2
20
lastDigit = digit
21
}
22
return result
23
};
Copied!
Template generated via Leetmark.

Problem:

Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string "".
Example 1:
1
Input: ["flower","flow","flight"]
2
Output: "fl"
Copied!
Example 2:
1
Input: ["dog","racecar","car"]
2
Output: ""
3
Explanation: There is no common prefix among the input strings.
Copied!
Note:
All given inputs are in lowercase letters a-z.

Solution:

ONE
JavaScript specific solution. Get the min len then narrow down the prefix.
1
/**
2
* @param {string[]} strs
3
* @return {string}
4
*/
5
let longestCommonPrefix = function (strs) {
6
if (strs.length > 0) {
7
let minLen = Math.min(...strs.map(s => s.length))
8
const anyStr = strs[0]
9
while (minLen) {
10
const prefix = anyStr.slice(0, minLen--)
11
if (strs.every(s => s.startsWith(prefix))) {
12
return prefix
13
}
14
}
15
}
16
return ''
17
};
Copied!
TWO
1
/**
2
* @param {string[]} strs
3
* @return {string}
4
*/
5
let longestCommonPrefix = function(strs) {
6
if (strs.length <= 0) { return '' }
7
8
let i = 0
9
while (strs.every(s => s[i] && s[i] === strs[0][i])) {
10
i++
11
}
12
return strs[0].slice(0, i)
13
};
Copied!
THREE
General solution. Build up the prefix.
1
/**
2
* @param {string[]} strs
3
* @return {string}
4
*/
5
let longestCommonPrefix = function (strs) {
6
let prefix = ''
7
if (strs.length > 0) {
8
for (let i = 0; ; i++) {
9
const c = strs[0][i]
10
if (!c) { return prefix }
11
for (let j = 0; j < strs.length; j++) {
12
if (strs[j][i] !== c) {
13
return prefix
14
}
15
}
16
prefix += c
17
}
18
}
19
return prefix
20
};
Copied!
Template generated via Leetmark.

15. 3Sum

Problem:

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
1
Given array nums = [-1, 0, 1, 2, -1, -4],
2
3
A solution set is:
4
[
5
[-1, 0, 1],
6
[-1, -1, 2]
7
]
Copied!

Solution:

To simplify the problem, sort the nums first.
If sorted[0] > 0 or sorted[last] < 0, return an empty set.
From i = 0 to len(sorted) - 2, pick sorted[i] as the first number of a possible triplet result.
Let l = i + 1, r = len(sorted) - 1, we want to narrow them down to enumerate all possible combinations.
  • l++ if sorted[i] + sorted[l] + sorted[r] > 0.
  • r-- if sorted[i] + sorted[l] + sorted[r] < 0.
Skip any duplicate number as we iterate to avoid duplicate triplets.
1
/**
2
* @param {number[]} nums
3
* @return {number[][]}
4
*/
5
let threeSum = function (nums) {
6
const len = nums.length
7
const sorted = nums.sort((a, b) => a - b)
8
const result = []
9
10
if (sorted[0] > 0 || sorted[len-1] < 0) {
11
return result
12
}
13
14
for (let i = 0; i < len - 2; i++) {
15
if (sorted[i] > 0) {
16
break
17
}
18
19
if (i > 0 && sorted[i] === sorted[i-1]) {
20
continue
21
}
22
23
const twoSum = 0 - sorted[i]
24
25
for (let l = i + 1, r = len - 1; l < r;) {
26
const diff = twoSum - sorted[l] - sorted[r]
27
if (diff > 0) {
28
l++
29
} else if (diff < 0) {
30
r--
31
} else {
32
result.push([sorted[i], sorted[l], sorted[r]])
33
while (++l < r && sorted[l] === sorted[l - 1]);
34
while (--r > l && sorted[r] === sorted[r + 1]);
35
}
36
}
37
}
38
39
return result
40
};
Copied!
Template generated via Leetmark.

Problem:

Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:
1
Given array nums = [-1, 2, 1, -4], and target = 1.
2
3
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
Copied!

Solution:

Simplified version of 15. 3Sum.
1
/**
2
* @param {number[]} nums
3
* @param {number} target
4
* @return {number}
5
*/
6
let threeSumClosest = function(nums, target) {
7
const len = nums.length
8
const sorted = nums.sort((a, b) => a - b)
9
10
let minDiff = Infinity
11
12
for (let i = 0; i < len - 2; i++) {
13
if (i > 0 && sorted[i] === sorted[i-1]) {
14
continue
15
}
16
17
const twoSum = target - sorted[i]
18
19
for (let l = i + 1, r = len - 1; l < r;) {
20
const diff = twoSum - sorted[l] - sorted[r]
21
if (diff === 0) {
22
return target
23
} else {
24
if (diff > 0) {
25
l++
26
} else {
27
r--
28
}
29
30
if (Math.abs(diff) < Math.abs(minDiff)) {
31
minDiff = diff
32
}
33
}
34
}
35
}
36
37
return target - minDiff
38
};
Copied!
Template generated via Leetmark.

Problem:

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Could not load image
200px-Telephone-keypad2
Example:
1
Input: "23"
2
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
Copied!
Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.

Solution:

ONE
JavaScript specific optimization.
Array.prototype.push accepts arbitrary arguments which enables tighter loops.
Also, appending string is faster than prepending.
1
/**
2
* @param {string} digits
3
* @return {string[]}
4
*/
5
let letterCombinations = function(digits) {
6
if (digits.length <= 0) { return [] }
7
8
const letters = [
9
,
10
,
11
['a', 'b', 'c'],
12
['d', 'e', 'f'],
13
['g', 'h', 'i'],
14
['j', 'k', 'l'],
15
['m', 'n', 'o'],
16
['p', 'q', 'r', 's'],
17
['t', 'u', 'v'],
18
['w', 'x', 'y', 'z'],
19
]
20
21
let result = ['']
22
23
for (let i = 0; i < digits.length; i++) {
24
const arr = letters[digits[i]]
25
let newResult = []
26
arr.forEach(c => newResult.push(...result.map(r => r + c)))
27
result = newResult
28
}
29
30
return result
31
};
Copied!
TWO
General recursive DFS solution.
1
/**
2
* @param {string} digits
3
* @return {string[]}
4
*/
5
let letterCombinations = function(digits) {
6
const letters = [,, 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
7
const result = []
8
if (digits.length > 0) {
9
dfs(digits, 0, '', letters, result)
10
}
11
return result
12
};
13
14
function dfs (digits, idigit, path, letters, result) {
15
if (idigit >= digits.length) {
16
result.push(path)
17
return
18
}
19
const str = letters[digits[idigit]]
20
for (let i = 0; i < str.length; i++) {
21
dfs(digits, idigit + 1, path + str[i], letters, result)
22
}
23
};
Copied!
Template generated via Leetmark.

18. 4Sum

Problem:

Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
The solution set must not contain duplicate quadruplets.
Example:
1
Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.
2
3
A solution set is:
4
[
5
[-1, 0, 0, 1],
6
[-2, -1, 1, 2],
7
[-2, 0, 0, 2]
8
]
Copied!

Solution:

Like 15. 3Sum and 16. 3Sum Closest. Wrap one more loop.
1
/**
2
* @param {number[]} nums
3
* @param {number} target
4
* @return {number[][]}
5
*/
6
let fourSum = function(nums, target) {
7
const len = nums.length
8
const sorted = nums.sort((a, b) => a - b)
9
const result = []
10
11
for (let k = 0; k < len - 3; k++) {
12
if (k > 0 && sorted[k] === sorted[k-1]) {
13
continue
14
}
15
16
const threeSum = target - sorted[k]
17
18
for (let i = k+1; i < len - 2; i++) {
19
if (i > k+1 && sorted[i] === sorted[i-1]) {
20
continue
21
}
22
23
const twoSum = threeSum - sorted[i]
24
25
for (let l = i + 1, r = len - 1; l < r;) {
26
const diff = twoSum - sorted[l] - sorted[r]
27
if (diff > 0) {
28
l++
29
} else if (diff < 0) {
30
r--
31
} else {
32
result.push([sorted[k], sorted[i], sorted[l], sorted[r]])
33
while (++l < r && sorted[l] === sorted[l - 1]);
34
while (--r > l && sorted[r] === sorted[r + 1]);
35
}
36
}
37
}
38
}
39
40
return result
41
};
Copied!
Template generated via Leetmark.

Problem:

Given a linked list, remove the n-th node from the end of list and return its head.
Example:
1
Given linked list: 1->2->3->4->5, and n = 2.
2
3
After removing the second node from the end, the linked list becomes 1->2->3->5.
Copied!
Note:
Given n will always be valid.
Follow up:
Could you do this in one pass?

Solution:

Set a pointer p1 for iterating, and p2 which is n nodes behind, pointing at the (n+1)-th node from the end of list.
Boundaries that should be awared of:
  • p2 could be one node before head, which means the head should be removed.
  • p2 could be larger than the length of the list (Though the description says n will always be valid, we take care of it anyway).
  • It should be p1.next touches the end rather than p1 because we want p1 pointing at the last node.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @param {number} n
11
* @return {ListNode}
12
*/
13
let removeNthFromEnd = function(head, n) {
14
let p1 = head
15
while (p1 && n--) {
16
p1 = p1.next
17
}
18
19
if (!p1) { return n ? head : head.next }
20
21
let p2 = head
22
while (p1.next) {
23
p1 = p1.next
24
p2 = p2.next
25
}
26
27
p2.next = p2.next.next
28
29
return head
30
};
Copied!
Template generated via Leetmark.

Problem:

Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
An input string is valid if:
  1. 1.
    Open brackets must be closed by the same type of brackets.
  2. 2.
    Open brackets must be closed in the correct order.
Note that an empty string is also considered valid.
Example 1:
1
Input: "()"
2
Output: true
Copied!
Example 2:
1
Input: "()[]{}"
2
Output: true
Copied!
Example 3:
1
Input: "(]"
2
Output: false
Copied!
Example 4:
1
Input: "([)]"
2
Output: false
Copied!
Example 5:
1
Input: "{[]}"
2
Output: true
Copied!

Solution:

Stack 101.
Whenever we meet a close bracket, we want to compare it to the last open bracket.
That is why we use stack to store open brackets: first in, last out.
And since there is only bracket characters, the last open bracket happens to be the last character.
1
/**
2
* @param {string} s
3
* @return {boolean}
4
*/
5
let isValid = function(s) {
6
const stack = []
7
const pairs = {
8
'}': '{',
9
']': '[',
10
')': '(',
11
}
12
for (const c of s) {
13
const open = pairs[c]
14
if (open) {
15
if (stack.pop() !== open) {
16
return false
17
}
18
} else {
19
stack.push(c)
20
}
21
}
22
return stack.length <= 0
23
};
Copied!
Template generated via Leetmark.

Problem:

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
Example:
1
Input: 1->2->4, 1->3->4
2
Output: 1->1->2->3->4->4
Copied!

Solution:

Keep tracking the head of two lists and keep moving the pointer of smaller one to the next node.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} l1
10
* @param {ListNode} l2
11
* @return {ListNode}
12
*/
13
let mergeTwoLists = function(l1, l2) {
14
let prehead = { next: null }
15
let p = prehead
16
let p1 = l1
17
let p2 = l2
18
while (p1 && p2) {
19
let pSel
20
if (p1.val < p2.val) {
21
pSel = p1
22
p1 = p1.next
23
} else {
24
pSel = p2
25
p2 = p2.next
26
}
27
p.next = pSel
28
p = pSel
29
}
30
31
p.next = p1 || p2
32
33
return prehead.next
34
};
35
Copied!
Template generated via Leetmark.

Problem:

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
1
[
2
"((()))",
3
"(()())",
4
"(())()",
5
"()(())",
6
"()()()"
7
]
Copied!

Solution:

ONE
Recursive DFS backtracking.
1
/**
2
* @param {number} n
3
* @return {string[]}
4
*/
5
let generateParenthesis = function(n) {
6
const result = []
7
if (n > 0) {
8
dfs(n, 0, 0, '', result)
9
}
10
return result
11
};
12
13
function dfs (n, nopen, nclose, path, result) {
14
if (path.length === n * 2) {
15
result.push(path)
16
return
17
}
18
19
if (nopen < n) {
20
dfs(n, nopen + 1, nclose, path + '(', result)
21
}
22
23
if (nclose < nopen) {
24
dfs(n, nopen, nclose + 1, path + ')', result)
25
}
26
};
Copied!
TWO
BFS.
1
/**
2
* @param {number} n
3
* @return {string[]}
4
*/
5
let generateParenthesis = function(n) {
6
if (n <= 0) { return [] }
7
8
const queue = [{
9
path: '(',
10
open: 1,
11
close: 0,
12
}]
13
14
while (true) {
15
const { path, open, close } = queue.shift()
16
if (open + close === n * 2) {
17
queue.unshift({ path, open, close })
18
break
19
}
20
21
if (open < n) {
22
queue.push({
23
path: path + '(',
24
open: open + 1,
25
close,
26
})
27
}
28
29
if (close < open) {
30
queue.push({
31
path: path + ')',
32
open,
33
close: close + 1,
34
})
35
}
36
}
37
38
return queue.map(x => x.path)
39
};
Copied!
Template generated via Leetmark.

Problem:

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
1
Input:
2
[
3
1->4->5,
4
1->3->4,
5
2->6
6
]
7
Output: 1->1->2->3->4->4->5->6
Copied!

Solution:

ONE
Extend the idea of 21. Merge Two Sorted Lists and compare N items at a time.
This is slow as it reaches O(N^2).
TWO
Priority Queue. O(N * log(K)).
Since JavaScript does not provide a standard built-in Priority Queue data structure, it is challenging to implement an efficient one barehanded.
THREE
Divide and conquer. Also O(N * log(K)).
Divide N lists into ceil(N/2) pairs and merge your way up.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode[]} lists
10
* @return {ListNode}
11
*/
12
let mergeKLists = function(lists) {
13
while (lists.length > 1) {
14
lists.unshift(mergeTwoLists(lists.pop(), lists.pop()))
15
}
16
return lists[0] || []
17
};
18
19
/**
20
* Definition for singly-linked list.
21
* function ListNode(val) {
22
* this.val = val;
23
* this.next = null;
24
* }
25
*/
26
/**
27
* @param {ListNode} l1
28
* @param {ListNode} l2
29
* @return {ListNode}
30
*/
31
function mergeTwoLists (l1, l2) {
32
let prehead = { next: null }
33
let p = prehead
34
let p1 = l1
35
let p2 = l2
36
while (p1 && p2) {
37
let pSel
38
if (p1.val < p2.val) {
39
pSel = p1
40
p1 = p1.next
41
} else {
42
pSel = p2
43
p2 = p2.next
44
}
45
p.next = pSel
46
p = pSel
47
}
48
49
p.next = p1 || p2
50
51
return prehead.next
52
};
Copied!
Template generated via Leetmark.

Problem:

Given a linked list, swap every two adjacent nodes and return its head.
Example:
1
Given 1->2->3->4, you should return the list as 2->1->4->3.
Copied!
Note:
  • Your algorithm should use only constant extra space.
  • You may not modify the values in the list's nodes, only nodes itself may be changed.

Solution:

  1. 1.
    Draw the nodes down on paper to reason about the relationships.
  2. 2.
    Pointing to every active node is an easy way to keep on track.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @return {ListNode}
11
*/
12
let swapPairs = function(head) {
13
const prehead = { next: head }
14
15
for (let p = prehead; p.next !== null && p.next.next !== null;) {
16
const p1 = p.next
17
const p2 = p1.next
18
p1.next = p2.next
19
p2.next = p1
20
p.next = p2
21
p = p1
22
}
23
24
return prehead.next
25
};
Copied!
Template generated via Leetmark.

Problem:

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
Example:
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5
Note:
  • Only constant extra memory is allowed.
  • You may not alter the values in the list's nodes, only nodes itself may be changed.

Solution:

  1. 1.
    Find the end node of a portion that needs to be reversed.
  2. 2.
    Get the next node of the end node.
  3. 3.
    Reverse the portion using the next node as edge(null) pointer.
  4. 4.
    Connect it back to the main linked list.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @param {number} k
11
* @return {ListNode}
12
*/
13
let reverseKGroup = function(head, k) {
14
const prehead = { next: head }
15
let p = prehead
16
while (true) {
17
let n = k
18
let pEndNext = p.next
19
while (pEndNext && n) {
20
pEndNext = pEndNext.next
21
n--
22
}
23
24
if (n !== 0) {
25
break
26
}
27
28
const nextp = p.next // The first node will be the last after reverse
29
p.next = reverseLinkList(p.next, pEndNext)
30
p = nextp
31
}
32
33
return prehead.next
34
};
35
36
function reverseLinkList (head, nullNode = null) {
37
let prev = nullNode
38
let curr = head
39
while (curr !== nullNode) {
40
const next = curr.next
41
curr.next = prev
42
prev = curr
43
curr = next
44
}
45
return prev
46
};
Copied!
Template generated via Leetmark.

Problem:

Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Example 1:
1
Given nums = [1,1,2],
2
3
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
4
5
It doesn't matter what you leave beyond the returned length.
Copied!
Example 2:
1
Given nums = [0,0,1,1,1,2,2,3,3,4],
2
3
Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.
4
5
It doesn't matter what values are set beyond the returned length.
Copied!
Clarification:
Confused why the returned value is an integer but your answer is an array?
Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.
Internally you can think of this:
1
// nums is passed in by reference. (i.e., without making a copy)
2
int len = removeDuplicates(nums);
3
4
// any modification to nums in your function would be known by the caller.
5
// using the length returned by your function, it prints the first len elements.
6
for (int i = 0; i < len; i++) {
7
print(nums[i]);
8
}
Copied!

Solution:

The result array can only be shorter. That is why we can build the array in-place with the new length.
1
/**
2
* @param {number[]} nums
3
* @return {number}
4
*/
5
let removeDuplicates = function(nums) {
6
let len = 0
7
for (let i = 0; i < nums.length; i++) {
8
if (nums[i] !== nums[i-1]) {
9
nums[len++] = nums[i]
10
}
11
}
12
return len
13
};
Copied!
Template generated via Leetmark.

Problem:

Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
The order of elements can be changed. It doesn't matter what you leave beyond the new length.
Example 1:
1
Given nums = [3,2,2,3], val = 3,
2
3
Your function should return length = 2, with the first two elements of nums being 2.
4
5
It doesn't matter what you leave beyond the returned length.
Copied!
Example 2:
1
Given nums = [0,1,2,2,3,0,4,2], val = 2,
2
3
Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4.
4
5
Note that the order of those five elements can be arbitrary.
6
7
It doesn't matter what values are set beyond the returned length.
Copied!
Clarification:
Confused why the returned value is an integer but your answer is an array?
Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.
Internally you can think of this:
1
// nums is passed in by reference. (i.e., without making a copy)
2
int len = removeElement(nums, val);
3
4
// any modification to nums in your function would be known by the caller.
5
// using the length returned by your function, it prints the first len elements.
6
for (int i = 0; i < len; i++) {
7
print(nums[i]);
8
}
Copied!

Solution:

The order does not matter. So just take the last number to fill the vacancy.
1
/**
2
* @param {number[]} nums
3
* @param {number} val
4
* @return {number}
5
*/
6
let removeElement = function(nums, val) {
7
let len = nums.length
8
for (let i = 0; i < len; i++) {
9
if (nums[i] === val) {
10
nums[i--] = nums[--len]
11
}
12
}
13
return len
14
};
Copied!
Template generated via Leetmark.

Problem:

Given two integers dividend and divisor, divide two integers without using multiplication, division and mod operator.
Return the quotient after dividing dividend by divisor.
The integer division should truncate toward zero.
Example 1:
1
Input: dividend = 10, divisor = 3
2
Output: 3
Copied!
Example 2:
1
Input: dividend = 7, divisor = -3
2
Output: -2
Copied!
Note:
  • Both dividend and divisor will be 32-bit signed integers.
  • The divisor will never be 0.
  • Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of this problem, assume that your function returns 231 − 1 when the division result overflows.

Solution:

Every decimal number can be represented as a0*2^0 + a1*2^1 + a2*2^2 + ... + an*2^n.
Replace multiplication and division with binary shifting.
1
/**
2
* @param {number} dividend
3
* @param {number} divisor
4
* @return {number}
5
*/
6
let divide = function(dividend, divisor) {
7
if (divisor === 0 ||
8
divisor === -1 && dividend < -2147483647 ||
9
dividend > 2147483647 ||
10
dividend < -2147483648
11
) {
12
return 2147483647
13
}
14
15
const isNegative = dividend < 0 && divisor >= 0 || dividend >= 0 && divisor < 0
16
const pDividend = Math.abs(dividend)
17
const pDivisor = Math.abs(divisor)
18
19
if (dividend === 0 || pDividend < pDivisor) { return 0 }
20
21
let doubling = pDivisor
22
let count = 1
23
while (doubling < pDividend && !(doubling & (1 << 30))) {
24
doubling <<= 1
25
count <<= 1
26
}
27
if (doubling > pDividend) {
28
doubling >>>= 1
29
count >>>= 1
30
}
31
32
const result = count + divide(pDividend - doubling, pDivisor)
33
return isNegative ? -result : result
34
};
Copied!
Template generated via Leetmark.

Problem:

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place and use only constant extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,31,3,2 3,2,11,2,3 1,1,51,5,1

Solution:

Observe a few longer examples and the pattern is self-evident.
Divide the list into two parts. The first half must be incremental and the second half must be decremental.
Reverse the second half and find the smallest number in it that is greater the last number of the first half.
Swap the two.
1
/**
2
* @param {number[]} nums
3
* @return {void} Do not return anything, modify nums in-place instead.
4
*/
5
let nextPermutation = function(nums) {
6
const len = nums.length
7
if (len <= 1) { return }
8
9
for (let i = len - 1; i > 0; i--) {
10
if (nums[i] > nums[i-1]) {
11
let t
12
for (let s = i, e = len-1; s < e; s++, e--) {
13
t = nums[s]
14
nums[s] = nums[e]
15
nums[e] = t
16
}
17
18
let j = len - 1
19
while (nums[j] <= nums[i-1]) {
20
j--
21
}
22
23
t = nums[j]
24
nums[j] = nums[i-1]
25
nums[i-1] = t
26
27
break
28
}
29
}
30
31
if (i === 0) {
32
nums.reverse()
33
}
34
};
Copied!
Template generated via Leetmark.

Problem:

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
Your algorithm's runtime complexity must be in the order of O(log n).
Example 1:
1
Input: nums = [4,5,6,7,0,1,2], target = 0
2
Output: 4
Copied!
Example 2:
1
Input: nums = [4,5,6,7,0,1,2], target = 3
2
Output: -1
Copied!

Solution:

Obviously the problem requires binary search.
The core idea of binary search is to pick the middle item and then decide to keep which half.
The precondition of it is the array must be sorted.
But take a closer look and we realize that only one of the two halves needs to be sorted. This is sufficient for us to know if the target is in that half. If not, then it must be in the other.
Whenever we choose a pivot, it must be in one of the two sorted parts of the rotated array.
  • If the pivot is in the left part. We know that the begin of the left part to the pivot are sorted.
  • Otherwise the pivot is in the right part. We know that the end of the right part to the pivot are sorted.
1
/**
2
* @param {number[]} nums
3
* @param {number} target
4
* @return {number}
5
*/
6
let search = function(nums, target) {
7
let s = 0
8
let e = nums.length - 1
9
10
while (s <= e) {
11
const p = (e + s) / 2 | 0
12
const pivot = nums[p]
13
14
if (pivot === target) {
15
return p
16
}
17
18
if (pivot < nums[e]) {
19
// right half is sorted
20
if (target > pivot && target <= nums[e]) {
21
// target is inside the right half
22
s = p + 1
23
} else {
24
e = p - 1
25
}
26
} else {
27
// left half is sorted
28
if (target < pivot && target >= nums[s]) {
29
// target is inside the left half
30
e = p - 1
31
} else {
32
s = p + 1
33
}
34
}
35
}
36
37
return -1
38
};
Copied!
Template generated via Leetmark.

Problem:

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm's runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
Example 1:
1
Input: nums = [5,7,7,8,8,10], target = 8
2
Output: [3,4]
Copied!
Example 2:
1
Input: nums = [5,7,7,8,8,10], target = 6
2
Output: [-1,-1]
Copied!

Solution:

Implement two variations of binary search to get the first and last matching positions.
They are basically the same as simple binary search except when we got the match, we mark the index and keep moving forward.
If we want to get the first, we dump the right half. Vice versa.
1
/**
2
* @param {number[]} nums
3
* @param {number} target
4
* @return {number[]}
5
*/
6
let searchRange = function(nums, target) {
7
let s = 0
8
let e = nums.length - 1
9
10
const first = searchFirst(nums, target, 0, nums.length - 1)
11
12
if (first === -1) {
13
return [-1, -1]
14
}
15
16
return [first, searchLast(nums, target, first, nums.length - 1)]
17
};
18
19
function searchFirst (nums, target, s, e) {
20
let result = -1
21
22
while (s <= e) {
23
const p = (s + e) / 2 | 0
24
const diff = nums[p] - target
25
if (diff === 0) {
26
result = p
27
e = p - 1
28
} else if (diff > 0) {
29
e = p - 1
30
} else {
31
s = s + 1
32
}
33
}
34
35
return result
36
};
37
38
function searchLast (nums, target, s, e) {
39
let result = -1
40
41
while (s <= e) {
42
const p = (s + e) / 2 | 0
43
const diff = nums[p] - target
44
if (diff === 0) {
45
result = p
46
s = p + 1
47
} else if (diff > 0) {
48
e = p - 1
49
} else {
50
s = s + 1
51
}
52
}
53
54
return result
55
};
Copied!
Template generated via Leetmark.

Problem:

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
Example 1:
1
Input: [1,3,5,6], 5
2
Output: 2
Copied!
Example 2:
1
Input: [1,3,5,6], 2
2
Output: 1
Copied!
Example 3:
1
Input: [1,3,5,6], 7
2
Output: 4
Copied!
Example 4:
1
Input: [1,3,5,6], 0
2
Output: 0
Copied!

Solution:

Same as simple binary search except it returns the start index when does not find a match.
1
/**
2
* @param {number[]} nums
3
* @param {number} target
4
* @return {number}
5
*/
6
let searchInsert = function(nums, target) {
7
let s = 0
8
let e = nums.length - 1
9
10
while (s <= e) {
11
const p = (s + e) / 2 | 0
12
const diff = nums[p] - target
13
if (diff === 0) {
14
return p
15
} else if (diff < 0) {
16
s = p + 1
17
} else {
18
e = p - 1
19
}
20
}
21
22
return s
23
};
Copied!
Template generated via Leetmark.

Problem:

Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
  1. 1.
    Each row must contain the digits 1-9 without repetition.
  2. 2.
    Each column must contain the digits 1-9 without repetition.
  3. 3.
    Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.
Could not load image
250px-Sudoku-by-L2G-20050714.svg.png
A partially filled sudoku which is valid.
The Sudoku board could be partially filled, where empty cells are filled with the character '.'.
Example 1:
1
Input:
2
[
3
["5","3",".",".","7",".",".",".","."],
4
["6",".",".","1","9","5",".",".","."],
5
[".","9","8",".",".",".",".","6","."],
6
["8",".",".",".","6",".",".",".","3"],
7
["4",".",".","8",".","3",".",".","1"],
8
["7",".",".",".","2",".",".",".","6"],
9
[".","6",".",".",".",".","2","8","."],
10
[".",".",".","4","1","9",".",".","5"],
11
[".",".",".",".","8",".",".","7","9"]
12
]
13
Output: true
Copied!
Example 2:
1
Input:
2
[
3
["8","3",".",".","7",".",".",".","."],
4
["6",".",".","1","9","5",".",".","."],
5
[".","9","8",".",".",".",".","6","."],
6
["8",".",".",".","6",".",".",".","3"],
7
["4",".",".","8",".","3",".",".","1"],
8
["7",".",".",".","2",".",".",".","6"],
9
[".","6",".",".",".",".","2","8","."],
10
[".",".",".","4","1","9",".",".","5"],
11
[".",".",".",".","8",".",".","7","9"]
12
]
13
Output: false
14
Explanation: Same as Example 1, except with the 5 in the top left corner being
15
modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
Copied!
Note:
  • A Sudoku board (partially filled) could be valid but is not necessarily solvable.
  • Only the filled cells need to be validated according to the mentioned rules.
  • The given board contain only digits 1-9 and the character '.'.
  • The given board size is always 9x9.

Solution:

Scan the board once.
1
/**
2
* @param {character[][]} board
3
* @return {boolean}
4
*/
5
let isValidSudoku = function(board) {
6
if (!board || board.length !== 9) { return false }
7
8
const newArray = () => []
9
const col = board.map(newArray)
10
const row = board.map(newArray)
11
const sub = board.map(newArray)
12
13
for (let r = 0; r < 9; r++) {
14
if (board[r].length !== 9) { return false }
15
16
for (let c = 0; c < 9; c++) {
17
const num = board[r][c]
18
const subOffset = 3 * (r / 3 | 0) + (c / 3 | 0)
19
if (num !== '.') {
20
if (!(num >= 1 && num <= 9) ||
21
row[r][num] ||
22
col[c][num] ||
23
sub[subOffset][num]
24
) {
25
return false
26
}
27
row[r][num] = true
28
col[c][num] = true
29
sub[subOffset][num] = true
30
}
31
}
32
}
33
34
return true
35
};
Copied!
Template generated via Leetmark.

Problem:

Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
  1. 1.
    Each of the digits 1-9 must occur exactly once in each row.
  2. 2.
    Each of the digits 1-9 must occur exactly once in each column.
  3. 3.
    Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
Empty cells are indicated by the character '.'.
A sudoku puzzle...
...and its solution numbers marked in red.
Note:
  • The given board contain only digits 1-9 and the character '.'.
  • You may assume that the given Sudoku puzzle will have a single unique solution.
  • The given board size is always 9x9.

Solution:

DFS + backtracking.
Just like 36. Valid Sudoku but instead of validating the board with three tables, we use these three tables to get all the valid numbers at a position. This is super fast as it skips a lot of redundant comparisons.
Every time we reach a position, we pick a possible solution and move on to the next position, which is an identical problem.
If the next position fails, we come back and try the next possible solution of the current position.
If all possible solutions fail, we just dump the current position and go back to the last position.
1
/**
2
* @param {character[][]} board
3
* @return {void} Do not return anything, modify board in-place instead.
4
*/
5
let solveSudoku = function(board) {
6
const newArray = () => []
7
const col = board.map(newArray)
8
const row = board.map(newArray)
9
const sub = board.map(newArray)
10
11
for (let r = 0; r < 9; r++) {
12
for (let c = 0; c < 9; c++) {
13
const num = +board[r][c]
14
if (num) {
15
const subOffset = 3 * (r / 3 | 0) + (c / 3 | 0)
16
row[r][num] = true
17
col[c][num] = true
18
sub[subOffset][num] = true
19
}
20
}
21
}
22
23
dfs(board, col, row, sub, 0)
24
};
25
26
function dfs (board, col, row, sub, pos) {
27
if (pos >= 81) { return true }
28
29
const r = pos / 9 | 0
30
const c = pos % 9
31
32
if (board[r][c] !== '.') {
33
return dfs(board, col, row, sub, pos + 1)
34
}
35
36
const subOffset = 3 * (r / 3 | 0) + (c / 3 | 0)
37
38
for (let num = 1; num <= 9; num++) {
39
if (!(row[r][num] || col[c][num] || sub[subOffset][num])) {
40
row[r][num] = true
41
col[c][num] = true
42
sub[subOffset][num] = true
43
44
if (dfs(board, col, row, sub, pos + 1)) {
45
board[r][c] = num + ''
46
return true
47
} else {
48
row[r][num] = false
49
col[c][num] = false
50
sub[subOffset][num] = false
51
}
52
}
53
}
54
55
return false
56
};
Copied!
Template generated via Leetmark.

Problem:

The count-and-say sequence is the sequence of integers with the first five terms as following:
1
1. 1
2
2. 11
3
3. 21
4
4. 1211
5
5. 111221
Copied!
1 is read off as "one 1" or 11. 11 is read off as "two 1s" or 21. 21 is read off as "one 2, then one 1" or 1211.
Given an integer n, generate the nth term of the count-and-say sequence.
Note: Each term of the sequence of integers will be represented as a string.
Example 1:
1
Input: 1
2
Output: "1"
Copied!
Example 2:
1
Input: 4
2
Output: "1211"
Copied!

Solution:

Just loop and grow the sequence.
ONE
JavaScript specific.
1
/**
2
* @param {number} n
3
* @return {string}
4
*/
5
let countAndSay = function(n) {
6
let num = '1'
7
8
while (--n > 0) {
9
num = num.match(/(\d)\1*/g).map(x => x.length + x[0]).join('')
10
}
11
12
return num
13
};
Copied!
TWO
General solution.
1
/**
2
* @param {number} n
3
* @return {string}
4
*/
5
let countAndSay = function(n) {
6
let num = '1'
7
8
while (--n > 0) {
9
let newNum = ''
10
for (let i = 0, accu = 1; i < num.length; i++, accu++) {
11
if (num[i] !== num[i+1]) {
12
newNum += accu + num[i]
13
accu = 0
14
}
15
}
16
num = newNum
17
}
18
19
return num
20
};
Copied!
Template generated via Leetmark.

Problem:

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
Note:
  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.
Example 1:
1
Input: candidates = [2,3,6,7], target = 7,
2
A solution set is:
3
[
4
[7],
5
[2,2,3]
6
]
Copied!
Example 2:
1
Input: candidates = [2,3,5], target = 8,
2
A solution set is:
3
[
4
[2,2,2,2],
5
[2,3,3],
6
[3,5]
7
]
Copied!

Solution:

DFS + Backtracking.
To prevent duplications, only loop the right side of the candidates.
1
/**
2
* @param {number[]} candidates
3
* @param {number} target
4
* @return {number[][]}
5
*/
6
let combinationSum = function(candidates, target) {
7
return dfs(candidates, target, [], [], 0)
8
};
9
10
function dfs (candidates, target, result, path, start) {
11
for (let i = start; i < candidates.length; i++) {
12
const cand = candidates[i]
13
14
if (cand > target) {
15
continue
16
}
17
18
path.push(cand)
19
if (cand === target) {
20
result.push(path.slice())
21
} else {
22
dfs(candidates, target - cand, result, path, i)
23
}
24
path.pop(cand)
25
}
26
27
return result
28
};
Copied!
Template generated via Leetmark.

Problem:

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
Each number in candidates may only be used once in the combination.
Note:
  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.
Example 1:
1
Input: candidates = [10,1,2,7,6,1,5], target = 8,
2
A solution set is:
3
[
4
[1, 7],
5
[1, 2, 5],
6
[2, 6],
7
[1, 1, 6]
8
]
Copied!
Example 2:
1
Input: candidates = [2,5,2,1,2], target = 5,
2
A solution set is:
3
[
4
[1,2,2],
5
[5]
6
]
Copied!

Solution:

Mostly the same as 39. Combination Sum.
Now the candidates might have duplicate numbers, so we need to sort it.
We can also safely return when number is larger than the target.
To prvent duplicate results, stop searching if the current number is same as the last.
Notice the number at start is immune by the rule because we assume that the current group of candidates begins at start.
1
/**
2
* @param {number[]} candidates
3
* @param {number} target
4
* @return {number[][]}
5
*/
6
let combinationSum2 = function(candidates, target) {
7
return dfs(candidates.sort((a, b) => a - b), target, [], [], 0)
8
};
9
10
function dfs (candidates, target, result, path, start) {
11
for (let i = start; i < candidates.length; i++) {
12
const cand = candidates[i]
13
14
if (cand > target) {
15
return result
16
}
17
18
if (i > start && cand === candidates[i-1]) {
19
continue
20
}
21
22
path.push(cand)
23
if (cand === target) {
24
result.push(path.slice())
25
} else {
26
dfs(candidates, target - cand, result, path, i + 1)
27
}
28
path.pop()
29
}
30
31
return result
32
};
Copied!
Template generated via Leetmark.

Problem:

Given an unsorted integer array, find the smallest missing positive integer.
Example 1:
1
Input: [1,2,0]
2
Output: 3
Copied!
Example 2:
1
Input: [3,4,-1,1]
2
Output: 2
Copied!
Example 3:
1
Input: [7,8,9,11,12]
2
Output: 1
Copied!
Note:
Your algorithm should run in O(n) time and uses constant extra space.

Solution:

The last requirement is why this problem is marked "hard". Though the solution feels like cheating: it modifies the array to mark numbers.
So the algorithm still requires O(n) space but O(1) extra space.
The core idea of the solution is, if the length of the array is n, then the smallest missing positive integer must be within [1, n+1].
Consider an edge-case scenario where the array is [1,2,...,n]. The smallest missing positive integer is n+1.
Now if one of these integers is missing in the array, that integer is the smallest missing positive integer.
If more than one are missing, pick the smallest.
So here we reuse the array and keep trying to put integer k into the slot indexed k-1 (via swapping).
1
/**
2
* @param {number[]} nums
3
* @return {number}
4
*/
5
let firstMissingPositive = function(nums) {
6
const n = nums.length
7
8
for (let i = 1; i < n; i++) {
9
while (nums[i] <= n && nums[i] !== nums[nums[i] - 1]) {
10
const t = nums[i]
11
nums[i] = nums[t - 1]
12
nums[t - 1] = t
13
}
14
}
15
16
for (let i = 0; i < n; i++) {
17
if (nums[i] !== i + 1) {
18
return i + 1
19
}
20
}
21
22
return n + 1
23
};
Copied!
Template generated via Leetmark.

Problem:

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
Example:
1
Input: [0,1,0,2,1,0,1,3,2,1,2,1]
2
Output: 6
Copied!

Solution:

Well explained by Leetcode official: https://leetcode.com/articles/trapping-rain-water/ .
1
/**
2
* @param {number[]} height
3
* @return {number}
4
*/
5
let trap = function(height) {
6
let i = 0
7
let j = height.length - 1
8
let lMax = 0
9
let rMax = 0
10
let result = 0
11
12
while (i < j) {
13
const left = height[i]
14
const right = height[j]
15
if (left < right) {
16
if (left < lMax) {
17
result += lMax - left
18
} else {
19
lMax = left
20
}
21
i++
22
} else {
23
if (right < rMax) {
24
result += rMax - right
25
} else {
26
rMax = right
27
}
28
j--
29
}
30
}
31
32
return result
33
};
Copied!
Template generated via Leetmark.

Problem:

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.
Example 1:
1
Input: num1 = "2", num2 = "3"
2
Output: "6"
Copied!
Example 2:
1
Input: num1 = "123", num2 = "456"
2
Output: "56088"
Copied!
Note:
  1. 1.
    The length of both num1 and num2 is < 110.
  2. 2.
    Both num1 and num2 contain only digits 0-9.
  3. 3.
    Both num1 and num2 do not contain any leading zero, except the number 0 itself.
  4. 4.
    You must not use any built-in BigInteger library or convert the inputs to integer directly.

Solution:

Same as we do multiplication on a paper.
1
/**
2
* @param {string} num1
3
* @param {string} num2
4
* @return {string}
5
*/
6
let multiply = function(num1, num2) {
7
const result = []
8
9
for (i = num1.length - 1; i >= 0; i--) {
10
for (j = num2.length - 1; j >= 0; j--) {
11
const sum = num1[i] * num2[j] + (result[i+j+1] || 0)
12
result[i+j] = (sum / 10 | 0) + (result[i+j] || 0)
13
result[i+j+1] = sum % 10
14
}
15
}
16
17
return result.join('').replace(/^0+(?=[0-9])/, '')
18
};
Copied!
Template generated via Leetmark.

Problem:

Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
Example:
1
Input: [2,3,1,1,4]
2
Output: 2
3
Explanation: The minimum number of jumps to reach the last index is 2.
4
Jump 1 step from index 0 to 1, then 3 steps to the last index.
Copied!
Note:
You can assume that you can always reach the last index.

Solution:

Greedy. Always pick the one that would allow to jump to the rightest.
1
/**
2
* @param {number[]} nums
3
* @return {number}
4
*/
5
let jump = function(nums) {
6
const len = nums.length
7
let jump = 0
8
for (let l = 0, r = 1; r < len; jump++) {
9
let rNext = r
10
for (let i = l; i < r; i++) {
11
const rNextAtmp = i + nums[i] + 1
12
if (rNextAtmp > rNext) {
13
rNext = rNextAtmp
14
}
15
}
16
l = r
17
r = rNext
18
}
19
return jump
20
};
Copied!
Template generated via Leetmark.

Problem:

Given a collection of distinct integers, return all possible permutations.
Example:
1
Input: [1,2,3]
2
Output:
3
[
4
[1,2,3],
5
[1,3,2],
6
[2,1,3],
7
[2,3,1],
8
[3,1,2],
9
[3,2,1]
10
]
Copied!

Solution:

One position at a time, pick a number from the unused set and put it in that position (by swapping). Then move on to the next.
1
/**
2
* @param {number[]} nums
3
* @return {number[][]}
4
*/
5
let permute = function(nums) {
6
const result = []
7
_permute(nums, 0, result)
8
return result
9
};
10
11
function _permute (nums, start, result) {
12
if (start === nums.length) {
13
return result.push(nums.slice())
14
}
15
16
const begin = nums[start]
17
for (let i = start; i < nums.length; i++) {
18
const next = nums[i]
19
20
nums[start] = next
21
nums[i] = begin
22
23
_permute(nums, start + 1, result)
24
25
nums[start] = begin
26
nums[i] = next
27
}
28
};
Copied!
Template generated via Leetmark.

Problem:

Given a collection of numbers that might contain duplicates, return all possible unique permutations.
Example:
1
Input: [1,1,2]
2
Output:
3
[
4
[1,1,2],
5
[1,2,1],
6
[2,1,1]
7
]
Copied!

Solution:

Same as 46. Permutations. To avoid duplication, when picking a number for a position, only pick the unused. Either sort the nums or use a set to mark.
1
/**
2
* @param {number[]} nums
3
* @return {number[][]}
4
*/
5
let permuteUnique = function(nums) {
6
const result = []
7
_permuteUnique(nums, 0, result)
8
return result
9
};
10
11
function _permuteUnique (nums, start, result) {
12
if (start === nums.length) {
13
result.push(nums.slice())
14
}
15
16
const used = new Set()
17
const begin = nums[start]
18
for (let i = start; i < nums.length; i++) {
19
const next = nums[i]
20
21
if (used.has(next)) {
22
continue
23
}
24
25
used.add(next)
26
27
nums[start] = next
28
nums[i] = begin
29
30
_permuteUnique(nums, start + 1, result)
31
32
nums[start] = begin
33
nums[i] = next
34
}
35
};
Copied!
Template generated via Leetmark.

Problem:

You are given an n x n 2D matrix representing an image.
Rotate the image by 90 degrees (clockwise).
Note:
You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
Example 1:
1
Given input matrix =
2
[
3
[1,2,3],
4
[4,5,6],
5
[7,8,9]
6
],
7
8
rotate the input matrix in-place such that it becomes:
9
[
10
[7,4,1],
11
[8,5,2],
12
[9,6,3]
13
]
Copied!
Example 2:
1
Given input matrix =
2
[
3
[ 5, 1, 9,11],
4
[ 2, 4, 8,10],
5
[13, 3, 6, 7],
6
[15,14,12,16]
7
],
8
9
rotate the input matrix in-place such that it becomes:
10
[
11
[15,13, 2, 5],
12
[14, 3, 4, 1],
13
[12, 6, 8, 9],
14
[16, 7,10,11]
15
]
Copied!

Solution:

Outside-in. Rotate one square at a time.
1
/**
2
* @param {number[][]} matrix
3
* @return {void} Do not return anything, modify matrix in-place instead.
4
*/
5
let rotate = function(matrix) {
6
if (!matrix || matrix.length <= 0) {
7
return
8
}
9
const width = matrix.length
10
const halfWidthFloor = Math.floor(width / 2)
11
const halfWidthCeil = Math.ceil(width / 2)
12
for (let i = 0; i < halfWidthFloor; i++) {
13
const iend = width - 1 - i
14
for (let j = 0; j < halfWidthCeil; j++) {
15
const jend = width - 1 - j
16
const tmp = matrix[i][j]
17
matrix[i][j] = matrix[jend][i];
18
matrix[jend][i] = matrix[iend][jend]
19
matrix[iend][jend] = matrix[j][iend]
20
matrix[j][iend] = tmp
21
}
22
}
23
};
Copied!
Template generated via Leetmark.

Problem:

Given an array of strings, group anagrams together.
Example:
1
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
2
Output:
3
[
4
["ate","eat","tea"],
5
["nat","tan"],
6
["bat"]
7
]
Copied!
Note:
  • All inputs will be in lowercase.
  • The order of your output does not matter.

Solution:

It's all about hashing the words.
ONE
Sort each word to get the key.
1
/**
2
* @param {string[]} strs
3
* @return {string[][]}
4
*/
5
let groupAnagrams = function(strs) {
6
let result = {};
7
for (let i = 0; i < strs.length; i++) {
8
const hash = strs[i].split('').sort().join('');
9
result[hash] = result[hash] || []
10
result[hash].push(strs[i])
11
}
12
return Object.values(result)
13
};
Copied!
TWO
Use the product of prime numbers to generate unique keys.
1
const prime = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101]
2
3
/**
4
* @param {string[]} strs
5
* @return {string[][]}
6
*/
7
let groupAnagrams = function(strs) {
8
const result = {};
9
for (let i = 0; i < strs.length; i++) {
10
const word = strs[i]
11
let hash = 1
12
for (let k = 0; k < word.length; k++) {
13
hash *= prime[word.charCodeAt(k) - 97]
14
}
15
result[hash] = result[hash] || []
16
result[hash].push(word)
17
}
18
return Object.values(result)
19
};
Copied!
Template generated via Leetmark.

Problem:

Implement pow(x, n), which calculates x raised to the power n (xn).
Example 1:
1
Input: 2.00000, 10
2
Output: 1024.00000
Copied!
Example 2:
1
Input: 2.10000, 3
2
Output: 9.26100
Copied!
Example 3:
1
Input: 2.00000, -2
2
Output: 0.25000
3
Explanation: 2-2 = 1/22 = 1/4 = 0.25
Copied!
Note:
  • -100.0 < x < 100.0
  • n is a 32-bit signed integer, within the range [−231, 231 − 1]

Solution:

1
x^n = x^(n/2) * x^(n/2), if n is even
2
x^n = x^((n-1)/2) * x^((n-1)/2) * x, if n is odd
Copied!
Corner cases:
  • n == 0
  • n < 0
Note here we can not use any bitwise operator, n = -2^31 might overflow.
1
/**
2
* @param {number} x
3
* @param {number} n
4
* @return {number}
5
*/
6
let myPow = function(x, n) {
7
if (n === 0) { return 1 }
8
if (n === 1) { return x }
9
if (n === -1) { return 1 / x }
10
if (n % 2 === 0) {
11
const res = myPow(x, n / 2)
12
return res * res
13
}
14
const res = myPow(x, (n - 1) / 2)
15
return x * res * res
16
};
Copied!
Template generated via Leetmark.

Problem:

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Could not load image
8-queens.png
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.
Example:
1
Input: 4
2
Output: [
3
[".Q..", // Solution 1
4
"...Q",
5
"Q...",
6
"..Q."],
7
8
["..Q.", // Solution 2
9
"Q...",
10
"...Q",
11
".Q.."]
12
]
13
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.
Copied!

Solution:

Allocate a n-length array queens. Each item represents a queen coordinate on the borad. Let index i be the row index, and queens[i] be the column index (or vice versa).
Now use the permutation algorithm from 46. Permutations to generate all possible queen positions, then test for diagonal.
ONE
1
/**
2
* @param {number} n
3
* @return {string[][]}
4
*/
5
let solveNQueens = function(n) {
6
const result = []
7
const queens = [...new Array(n)].map((_, i) => i)
8
_solveNQueens(queens, 0, result)
9
return result
10
};
11
12
function _solveNQueens (queens, iStart, result) {
13
if (iStart === queens.length) {
14
for (let i = 0; i < queens.length; i += 1) {
15
for (let j = i + 1; j < queens.length; j += 1) {
16
if (Math.abs(i - j) === Math.abs(queens[i] - queens[j])) {
17
return
18
}
19
}
20
}
21
return result.push(_genBoard(queens))
22
}
23
24
const start = queens[iStart]
25
for (let i = iStart; i < queens.length; i++) {
26
const next = queens[i]
27
28
queens[iStart] = next
29
queens[i] = start
30
31
_solveNQueens(queens, iStart + 1, result)
32
33
queens[iStart] = start
34
queens[i] = next
35
}
36
};
37
38
function _genBoard (queens) {
39
const board = []
40
for (let i = 0; i < queens.length; i++) {
41
let row = ''
42
for (let j = 0; j < queens.length; j++) {
43
row += queens[i] === j ? 'Q' : '.'
44
}
45
board.push(row)
46
}
47
return board
48
};
Copied!
This is slow because we test diagonal in the end. We can do a tree pruning by moving it right before diving into the next recursion.
TWO
1
/**
2
* @param {number} n
3
* @return {string[][]}
4
*/
5
let solveNQueens = function(n) {
6
const result = []
7
const queens = [...new Array(n)].map((_, i) => i)
8
_solveNQueens(queens, 0, result)
9
return result
10
};
11
12
function _solveNQueens (queens, iStart, result) {
13
if (iStart === queens.length) {
14
return result.push(_genBoard(queens))
15
}
16
17
const start = queens[iStart]
18
for (let i = iStart; i < queens.length; i++) {
19
const next = queens[i]
20
21
queens[iStart] = next
22
queens[i] = start
23
24
if (_testDiagonal(queens, iStart)) {
25
_solveNQueens(queens, iStart + 1, result)
26
}
27
28
queens[iStart] = start
29
queens[i] = next
30
}
31
};
32
33
function _testDiagonal(queens, iStart) {
34
for (let i = 0; i < iStart; i++) {
35
if (Math.abs(queens[iStart] - queens[i]) === iStart - i) {
36
return false
37
}
38
}
39
return true
40
};
41
42
function _genBoard (queens) {
43
const board = []
44
for (let i = 0; i < queens.length; i++) {
45
let row = ''
46
for (let j = 0; j < queens.length; j++) {
47
row += queens[i] === j ? 'Q' : '.'
48
}
49
board.push(row)
50
}
51
return board
52
};
Copied!
Template generated via Leetmark.

Problem:

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Could not load image
8-queens.png
Given an integer n, return the number of distinct solutions to the n-queens puzzle.
Example:
1
Input: 4
2
Output: 2
3
Explanation: There are two distinct solutions to the 4-queens puzzle as shown below.
4
[
5
[".Q..", // Solution 1
6
"...Q",
7
"Q...",
8
"..Q."],
9
10
["..Q.", // Solution 2
11
"Q...",
12
"...Q",
13
".Q.."]
14
]
Copied!

Solution:

Just modify 51. N-Queens.
1
/**
2
* @param {number} n
3
* @return {string[][]}
4
*/
5
let totalNQueens = function(n) {
6
return _totalNQueens([...new Array(n)].map((_, i) => i), 0)
7
};
8
9
function _totalNQueens (queens, iStart, result) {
10
if (iStart === queens.length) {
11
return 1
12
}
13
14
let count = 0
15
16
const start = queens[iStart]
17
for (let i = iStart; i < queens.length; i++) {
18
const next = queens[i]
19
20
queens[iStart] = next
21
queens[i] = start
22
23
if (_testDiagonal(queens, iStart)) {
24
count += _totalNQueens(queens, iStart + 1, result)
25
}
26
27
queens[iStart] = start
28
queens[i] = next
29
}
30
31
return count
32
};
33
34
function _testDiagonal(queens, iStart) {
35
for (let i = 0; i < iStart; i++) {
36
if (Math.abs(queens[iStart] - queens[i]) === iStart - i) {
37
return false
38
}
39
}
40
return true
41
};
Copied!
Template generated via Leetmark.

Problem:

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
1
Input: [-2,1,-3,4,-1,2,1,-5,4],
2
Output: 6
3
Explanation: [4,-1,2,1] has the largest sum = 6.
Copied!
Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

Solution:

DP.
Define f(i) to be the largest sum of a contiguous subarray that ends with nums[i].
If f(i-1) is negative, then nums[i] must be greater than f(i-1) + nums[i].
1
f(0) = nums[0]
2
f(i) = max( f(i-1), 0 ) + nums[i]
Copied!
Then return the largest one.
1
/**
2
* @param {number[]} nums
3
* @return {number}
4
*/
5
let maxSubArray = function(nums) {
6
const len = nums.length
7
if (len <= 0) { return 0 }
8
const dp = [nums[0]]
9
for (let i = 1; i < len; i++) {
10
dp[i] = Math.max(dp[i-1], 0) + nums[i]
11
}
12
return Math.max(...dp)
13
};
Copied!
We can also compress the dp array:
1
/**
2
* @param {number[]} nums
3
* @return {number}
4
*/
5
let maxSubArray = function(nums) {
6
let dp = nums[0]
7
let max = dp || 0
8
for (let i = 1; i < nums.length; i++) {
9
max = Math.max(max, dp = Math.max(dp, 0) + nums[i])
10
}
11
return max
12
};
Copied!
Template generated via Leetmark.

Problem:

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
Example 1:
1
Input:
2
[
3
[ 1, 2, 3 ],
4
[ 4, 5, 6 ],
5
[ 7, 8, 9 ]
6
]
7
Output: [1,2,3,6,9,8,7,4,5]
Copied!
Example 2:
1
Input:
2
[
3
[1, 2, 3, 4],
4
[5, 6, 7, 8],
5
[9,10,11,12]
6
]
7
Output: [1,2,3,4,8,12,11,10,9,5,6,7]
Copied!

Solution:

Loop outside-in. Break each cycle into four stages. Note that the last two stages need at least two rows/columns.
1
/**
2
* @param {number[][]} matrix
3
* @return {number[]}
4
*/
5
let spiralOrder = function(matrix) {
6
const result = []
7
const height = matrix.length
8
if (height <= 1) { return matrix[0] || result }
9
const width = matrix[0].length
10
if (width <= 0) { return result }
11
12
const end = (Math.min(width, height) + 1) / 2 | 0
13
for (let start = 0; start < end; start++) {
14
const rowEnd = height - start - 1
15
const colEnd = width - start - 1
16
for (let col = start; col <= colEnd; col++) {
17
result.push(matrix[start][col])
18
}
19
for (let row = start + 1; row <= rowEnd; row++) {
20
result.push(matrix[row][colEnd])
21
}
22
if (rowEnd > start) {
23
for (let col = colEnd - 1; col >= start ; col--) {
24
result.push(matrix[rowEnd][col])
25
}
26
}
27
if (colEnd > start) {
28
for (let row = rowEnd - 1; row > start ; row--) {
29
result.push(matrix[row][start])
30
}
31
}
32
}
33
return result
34
};
Copied!
Template generated via Leetmark.

Problem:

Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
Example 1:
1
Input: [2,3,1,1,4]
2
Output: true
3
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Copied!
Example 2:
1
Input: [3,2,1,0,4]
2
Output: false
3
Explanation: You will always arrive at index 3 no matter what. Its maximum
4
jump length is 0, which makes it impossible to reach the last index.
Copied!

Solution:

ONE
See 45. Jump Game II. If the range does not expand at some point, we know it is stuck.
1
/**
2
* @param {number[]} nums
3
* @return {boolean}
4
*/
5
let canJump = function(nums) {
6
for (let l = 0, r = 1; r < nums.length;) {
7
let rNext = r
8
for (let i = l; i < r; i++) {
9
const rNextAtmp = i + nums[i] + 1
10
if (rNextAtmp > rNext) {
11
rNext = rNextAtmp
12
}
13
}
14
if (rNext <= r) { return false }
15
l = r
16
r = rNext
17
}
18
return true
19
};
Copied!
TWO
If we view it backward, and if the range of nums[n-2] covers nums[n-1], then we can safely make n-2 the new destination point, and so on.
If nums[0] can cover the last destination point, it is good.
1
/**
2
* @param {number[]} nums
3
* @return {boolean}
4
*/
5
let canJump = function(nums) {
6
let des = nums.length - 1
7
for (let i = des - 1; i > 0; i--) {
8
if (nums[i] + i >= des) {
9
des = i
10
}
11
}
12
return nums[0] >= des
13
};
Copied!
Template generated via Leetmark.

Problem:

Given a collection of intervals, merge all overlapping intervals.
Example 1:
1
Input: [[1,3],[2,6],[8,10],[15,18]]
2
Output: [[1,6],[8,10],[15,18]]
3
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
Copied!
Example 2:
1
Input: [[1,4],[4,5]]
2
Output: [[1,5]]
3
Explanation: Intervals [1,4] and [4,5] are considerred overlapping.
Copied!

Solution:

Sort then merge.
1
/**
2
* Definition for an interval.
3
* function Interval(start, end) {
4
* this.start = start;
5
* this.end = end;
6
* }
7
*/
8
/**
9
* @param {Interval[]} intervals
10
* @return {Interval[]}
11
*/
12
let merge = function(intervals) {
13
if (intervals.length <= 1) { return intervals }
14
intervals.sort((a, b) => (a.start - b.start) || (a.end - b.end))
15
let last = new Interval(intervals[0].start, intervals[0].end)
16
const result = [last]
17
for (let i = 1; i < intervals.length; i++) {
18
const { start, end } = intervals[i]
19
if (start > last.end) {
20
last = new Interval(start, end)
21
result.push(last)
22
} else if (end > last.end) {
23
last.end = end
24
}
25
}
26
return result
27
};
Copied!
Template generated via Leetmark.

Problem:

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
You may assume that the intervals were initially sorted according to their start times.
Example 1:
1
Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
2
Output: [[1,5],[6,9]]
Copied!
Example 2:
1
Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
2
Output: [[1,2],[3,10],[12,16]]
3
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].
Copied!

Solution:

The logic of the solution is pretty straight forward. Just need to carefully think through all the edge cases. It is better to choose readability over performance.
1
/**
2
* Definition for an interval.
3
* function Interval(start, end) {
4
* this.start = start;
5
* this.end = end;
6
* }
7
*/
8
/**
9
* @param {Interval[]} intervals
10
* @param {Interval} newInterval
11
* @return {Interval[]}
12
*/
13
let insert = function(intervals, newInterval) {
14
const result = []
15
const p = new Interval(newInterval.start, newInterval.end)
16
for (let i = 0; i < intervals.length; i++) {
17
const { start, end } = intervals[i]
18
if (start > p.end) {
19
break
20
}
21
22
if (end < p.start) {
23
result.push(intervals[i])
24
continue
25
}
26
27
if (start < p.start) {
28
p.start = start
29
}
30
31
if (end > p.end) {
32
p.end = end
33
}
34
}
35
return [...result, p, ...intervals.slice(i)]
36
};
Copied!
Template generated via Leetmark.

Problem:

Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string.
If the last word does not exist, return 0.
Note: A word is defined as a character sequence consists of non-space characters only.
Example:
1
Input: "Hello World"
2
Output: 5
Copied!

Solution:

JavaScript specific solutions:
ONE
1
/**
2
* @param {string} s
3
* @return {number}
4
*/
5
let lengthOfLastWord = function(s) {
6
return (/\w+$/.exec(s) || [''])[0].length
7
};
Copied!
TWO
Super fast. split will guarantee that there is at least one item in the resulted array.
1
/**
2
* @param {string} s
3
* @return {number}
4
*/
5
let lengthOfLastWord = function(s) {
6
return s.trim().split(' ').pop().length
7
};
Copied!
THREE
General solution.
1
/**
2
* @param {string} s
3
* @return {number}
4
*/
5
let lengthOfLastWord = function(s) {
6
let end = s.length - 1
7
while (end >= 0 && s[end] === ' ') {
8
end--
9
}
10
11
let start = end
12
while (start >= 0 && s[start] !== ' ') {
13
start--
14
}
15
16
return end - start
17
};
Copied!
Template generated via Leetmark.

Problem:

Given a positive integer n, generate a square matrix filled with elements from 1 to n2 in spiral order.
Example:
1
Input: 3
2
Output:
3
[
4
[ 1, 2, 3 ],
5
[ 8, 9, 4 ],
6
[ 7, 6, 5 ]
7
]
Copied!

Solution:

Straight-forward.
1
/**
2
* @param {number} n
3
* @return {number[][]}
4
*/
5
let generateMatrix = function(n) {
6
const matrix = [...new Array(n)].map(() => [])
7
const halfN = (n + 1) / 2 | 0
8
let count = 1
9
for (let start = 0; start < halfN; start++) {
10
const end = n - start - 1
11
for (let col = start; col <= end; col++) {
12
matrix[start][col] = count++
13
}
14
for (let row = start + 1; row <= end; row++) {
15
matrix[row][end] = count++
16
}
17
for (let col = end - 1; col >= start; col--) {
18
matrix[end][col] = count++
19
}
20
for (let row = end - 1; row > start; row--) {
21
matrix[row][start] = count++
22
}
23
}
24
return matrix
25
};
Copied!
Template generated via Leetmark.

Problem:

The set [1,2,3,...,*n*] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order, we get the following sequence for n = 3:
  1. 1.
    "123"
  2. 2.
    "132"
  3. 3.
    "213"
  4. 4.
    "231"
  5. 5.
    "312"
  6. 6.
    "321"
Given n and k, return the kth permutation sequence.
Note:
  • Given n will be between 1 and 9 inclusive.
  • Given k will be between 1 and n! inclusive.
Example 1:
1
Input: n = 3, k = 3
2
Output: "213"
Copied!
Example 2:
1
Input: n = 4, k = 9
2
Output: "2314"
Copied!

Solution:

The order of the sequence is fixed hence can be calculated. We can view the process as picking digits from a sorted set [1...n].
Each digit appears (n-1)! times in result[0]. And for a fixed result[0] each digit appears (n-2)! times in result[1]. So on.
We also need k-- to convert k into index so that k <= (n-1)! maps 0 (and get 1 from the set).
1
/**
2
* @param {number} n
3
* @param {number} k
4
* @return {string}
5
*/
6
let getPermutation = function(n, k) {
7
const digits = []
8
let factorial = 1
9
for (let i = 1; i <= n; i++) {
10
digits.push(i)
11
factorial *= i
12
}
13
14
k--
15
16
let result = ''
17
while (n > 0) {
18
factorial /= n
19
result += digits.splice(k / factorial | 0, 1)[0]
20
k %= factorial
21
n--
22
}
23
24
return result
25
};
Copied!
Template generated via Leetmark.

Problem:

Given a linked list, rotate the list to the right by k places, where k is non-negative.
Example 1:
1
Input: 1->2->3->4->5->NULL, k = 2
2
Output: 4->5->1->2->3->NULL
3
Explanation:
4
rotate 1 steps to the right: 5->1->2->3->4->NULL
5
rotate 2 steps to the right: 4->5->1->2->3->NULL
Copied!
Example 2:
1
Input: 0->1->2->NULL, k = 4
2
Output: 2->0->1->NULL
3
Explanation:
4
rotate 1 steps to the right: 2->0->1->NULL
5
rotate 2 steps to the right: 1->2->0->NULL
6
rotate 3 steps to the right: 0->1->2->NULL
7
rotate 4 steps to the right: 2->0->1->NULL
Copied!

Solution:

Classic two-pointers chasing except the k could be larger than the length of this list.
We first attempt to locate the right pointer while also recording the length of the list.
If we hit the end of list and still do not have the right pointer, we know k is larger than the length.
Locate the right pointer again with k % len.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @param {number} k
11
* @return {ListNode}
12
*/
13
let rotateRight = function(head, k) {
14
if (head === null || k <= 0) { return head }
15
16
let right = head
17
let len = 0
18
let kk = k
19
while (right !== null && kk > 0) {
20
right = right.next
21
kk--
22
len++
23
}
24
25
if (kk > 0) {
26
right = head
27
kk = k % len
28
while (kk--) {
29
right = right.next
30
}
31
}
32
33
if (right !== null) {
34
let left = head
35
while (right.next !== null) {
36
left = left.next
37
right = right.next
38
}
39
right.next = head
40
head = left.next
41
left.next = null
42
}
43
44
return head
45
};
Copied!
Template generated via Leetmark.

Problem:

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
How many possible unique paths are there?
Could not load image
robot_maze.png
Above is a 7 x 3 grid. How many possible unique paths are there?
Note: m and n will be at most 100.
Example 1:
1
Input: m = 3, n = 2
2
Output: 3
3
Explanation:
4
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
5
1. Right -> Right -> Down
6
2. Right -> Down -> Right
7
3. Down -> Right -> Right
Copied!
Example 2:
1
Input: m = 7, n = 3
2
Output: 28
Copied!

Solution:

DP.
Define f(i, j) to be the number of total unique paths from (0, 0) to (i, j).
1
f(i, 0) = 1
2
f(0, j) = 1
3
f(i, j) = f(i-1, j) + f(i, j-1)
Copied!
Only two previous states are dependant. Use dynamic array to reduce memory allocation.
1
/**
2
* @param {number} m
3
* @param {number} n
4
* @return {number}
5
*/
6
let uniquePaths = function(m, n) {
7
const dp = new Array(m).fill(1)
8
while (--n > 0) {
9
for (let i = 1; i < m; i++) {
10
dp[i] += dp[i-1]
11
}
12
}
13
return dp[m-1] || 1
14
};
Copied!
Template generated via Leetmark.

Problem:

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example:
1
Input:
2
[
3
[1,3,1],
4
[1,5,1],
5
[4,2,1]
6
]
7
Output: 7
8
Explanation: Because the path 1→3→1→1→1 minimizes the sum.
Copied!

Solution:

Define f(i, j) to be the min sum from (0, 0) to (i, j).
1
f(0, 0) = grid[0][0]
2
f(0, j) = f(0, j-1) + grid[0][j], j > 0
3
f(i, 0) = f(i-1, 0) + grid[i][0], i > 0
4
f(i, j) = min( f(i-1, j), f(i, j-1) ) + grid[i][j], j > 0 && i > 0
Copied!
Only two previous states are dependant. Use dynamic array to reduce memory allocation.
1
/**
2
* @param {number[][]} grid
3
* @return {number}
4
*/
5
let minPathSum = function(grid) {
6
const height = grid.length
7
if (height <= 0) { return 0 }
8
const width = grid[0].length
9
if (width <= 0) { return 0 }
10
11
const dp = new Array(width).fill(Infinity)
12
dp[0] = 0
13
for (let i = 0; i < height; i++) {
14
dp[0] += grid[i][0]
15
for (let j = 1; j < width; j++) {
16
dp[j] = Math.min(dp[j], dp[j-1]) + grid[i][j]
17
}
18
}
19
20
return dp[width-1] || 0
21
};
Copied!
Template generated via Leetmark.

Problem:

Validate if a given string is numeric.
Some examples: "0" => true " 0.1 " => true "abc" => false "1 a" => false "2e10" => true
Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one.
Update (2015-02-10): The signature of the C++ function had been updated. If you still see your function signature accepts a const char * argument, please click the reload button to reset your code definition.

Solution:

JavaScript specific solutions:
ONE
  • Math.abs will first convert the argument to number.
  • Math.abs(' ') === 0.
1
/**
2
* @param {string} s
3
* @return {boolean}
4
*/
5
let isNumber = function(s) {
6
return !!s.trim() && Math.abs(s) >= 0
7
};
Copied!
TWO
  • isNaN will first convert the argument to number.
  • isNaN(' ') === false.
1
/**
2
* @param {string} s
3
* @return {boolean}
4
*/
5
let isNumber = function(s) {
6
return !!s.trim() && !isNaN(s)
7
};
Copied!
THREE
General solution. Take a look at the ECMA Spec.
Similary, we can define our own syntax, which requires a few changes:
1
SignedDecimalLiteral::
2
DecimalLiteral
3
+ DecimalLiteral
4
- DecimalLiteral
5
6
DecimalLiteral::
7
DecimalDigits . [DecimalDigits] [ExponentPart]
8
. DecimalDigits [ExponentPart]
9
DecimalDigits [ExponentPart]
10
11
DecimalDigits::
12
DecimalDigit
13
DecimalDigits DecimalDigit
14
15
DecimalDigit:: one of
16
0123456789
17
18
ExponentPart::
19
ExponentIndicator SignedInteger
20
21
ExponentIndicator::one of
22
eE
23
24
SignedInteger::
25
DecimalDigits
26
+ DecimalDigits
27
- DecimalDigits
Copied!
Now implement the parser. It is much easier now because we have a clear mental map of the syntax.
1
/**
2
* @param {string} s
3
* @return {boolean}
4
*/
5
let isNumber = function(s) {
6
let start = 0
7
while (s[start] === ' ') {
8
start++
9
}
10
if (s[start] === '+' || s[start] === '-') {
11
start++
12
}
13
let nextIndex = parseDecimalLiteral(s, start)
14
while (s[nextIndex] === ' ') {
15
nextIndex++
16
}
17
return nextIndex === s.length
18
}
19
20
/**
21
* @param {string} s
22
* @param {number} start - start index
23
* @return {number} next index, -1 means error
24
*/
25
function parseDecimalLiteral (s, start) {
26
let nextIndex = -1
27
if (s[start] === '.') {
28
nextIndex = parseDecimalDigits(s, start + 1)
29
if (nextIndex === -1) { return -1 }
30
} else {
31
nextIndex = parseDecimalDigits(s, start)
32
if (nextIndex === -1) { return -1 }
33
34
if (s[nextIndex] === '.') {
35
const optNextIndex = parseDecimalDigits(s, ++nextIndex)
36
if (optNextIndex !== -1) {
37
nextIndex = optNextIndex
38
}
39
}
40
}
41
42
const optNextIndex = parseExponentPart(s, nextIndex)
43
return optNextIndex === -1 ? nextIndex : optNextIndex
44
}
45
46
/**
47
* @param {string} s
48
* @param {number} start - start index
49
* @return {number} next index, -1 means error
50
*/
51
function parseDecimalDigits (s, start) {
52
if (start === s.length) { return -1 }
53
54
for (let i = start; i < s.length; i++) {
55
const digit = s.charCodeAt(i) - 48
56
if (!(digit >= 0 && digit <= 9)) {
57
return i === start ? -1 : i
58
}
59
}
60
return s.length
61
}
62
63
/**
64
* @param {string} s
65
* @param {number} start - start index
66
* @return {number} next index, -1 means error
67
*/
68
function parseDecimalIntegerLiteral (s, start) {
69
if (start === s.length) { return -1 }
70
71
let nextIndex = start
72
if (s[start] === '0') {
73
nextIndex++
74
}
75
76
const digit = s.charCodeAt(nextIndex) - 48
77
if (!(digit > 0 && digit <= 9)) {
78
return nextIndex === start ? -1 : nextIndex
79
}
80
nextIndex++
81
82
const optNextIndex = parseDecimalDigits (s, nextIndex)
83
return optNextIndex === -1 ? nextIndex : optNextIndex
84
}
85
86
/**
87
* @param {string} s
88
* @param {number} start - start index
89
* @return {number} next index, -1 means error
90
*/
91
function parseExponentPart (s, start) {
92
if (s[start] !== 'e' && s[start] !== 'E') {
93
return -1
94
}
95
96
let nextIndex = start + 1
97
if (s[nextIndex] === '+' || s[nextIndex] === '-') {
98
nextIndex++
99
}
100
101
return parseDecimalDigits(s, nextIndex)
102
}
Copied!
Template generated via Leetmark.

Problem:

Given a non-empty array of digits representing a non-negative integer, plus one to the integer.
The digits are stored such that the most significant digit is at the head of the list, and each element in the array contain a single digit.
You may assume the integer does not contain any leading zero, except the number 0 itself.
Example 1:
1
Input: [1,2,3]
2
Output: [1,2,4]
3
Explanation: The array represents the integer 123.
Copied!
Example 2:
1
Input: [4,3,2,1]
2
Output: [4,3,2,2]
3
Explanation: The array represents the integer 4321.
Copied!

Solution:

ONE
JavaScript specific solution. Note that unshift is much slower that expanding.
1
/**
2
* @param {number[]} digits
3
* @return {number[]}
4
*/
5
let plusOne = function(digits) {
6
for (let i = digits.length - 1; i >= 0; i--) {
7
if (digits[i] < 9) {
8
digits[i]++
9
return digits
10
}
11
digits[i] = 0
12
}
13
return [1, ...digits]
14
};
Copied!
TWO
General solution.
1
/**
2
* @param {number[]} digits
3
* @return {number[]}
4
*/
5
let plusOne = function(digits) {
6
for (let i = digits.length - 1; i >= 0; i--) {
7
if (digits[i] < 9) {
8
digits[i]++
9
return digits
10
}
11
digits[i] = 0
12
}
13
14
for (let i = digits.length; i > 0; i--) {
15
digits[i] = digits[i-1]
16
}
17
digits[0] = 1
18
19
return digits
20
};
Copied!
Template generated via Leetmark.

Problem:

Given an array of words and a width maxWidth, format the text such that each line has exactly maxWidth characters and is fully (left and right) justified.
You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly maxWidth characters.
Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right.
For the last line of text, it should be left justified and no extra space is inserted between words.
Note:
  • A word is defined as a character sequence consisting of non-space characters only.
  • Each word's length is guaranteed to be greater than 0 and not exceed maxWidth.
  • The input array words contains at least one word.
Example 1:
1
Input:
2
words = ["This", "is", "an", "example", "of", "text", "justification."]
3
maxWidth = 16
4
Output:
5
[
6
"This is an",
7
"example of text",
8
"justification. "
9
]
Copied!
Example 2:
1
Input:
2
words = ["What","must","be","acknowledgment","shall","be"]
3
maxWidth = 16
4
Output:
5
[
6
"What must be",
7
"acknowledgment ",
8
"shall be "
9
]
10
Explanation: Note that the last line is "shall be " instead of "shall be",
11
because the last line must be left-justified instead of fully-justified.
12
Note that the second line is also left-justified becase it contains only one word.
Copied!
Example 3:
1
Input:
2
words = ["Science","is","what","we","understand","well","enough","to","explain",
3
"to","a","computer.","Art","is","everything","else","we","do"]
4
maxWidth = 20
5
Output:
6
[
7
"Science is what we",
8
"understand well",
9
"enough to explain to",
10
"a computer. Art is",
11
"everything else we",
12
"do "
13
]
Copied!

Solution:

  • Count the current line width (plus 1 space between each two words).
  • When a line is full:
    • If there is only one word, pad spaces at the end.
    • Otherwise calculate the gap length using Math.ceil.
  • Handle the last line.
1
/**
2
* @param {string[]} words
3
* @param {number} maxWidth
4
* @return {string[]}
5
*/
6
let fullJustify = function(words, maxWidth) {
7
let start = 0
8
let end = 1
9
let lineLen = words[start].length
10
const result = []
11
12
while (end < words.length) {
13
const newLen = words[end].length + 1 + lineLen
14
if (newLen <= maxWidth) {
15
lineLen = newLen
16
} else {
17
let line = ''
18
let nWords = end - start
19
if (nWords === 1) {
20
line = words[start].padEnd(maxWidth)
21
} else {
22
let nSpaces = maxWidth - (lineLen - (nWords - 1))
23
for (let i = start; i < end; i++) {
24
const gap = Math.ceil(nSpaces / (end - i - 1))
25
line += words[i] + ' '.repeat(gap)
26
nSpaces -= gap
27
}
28
}
29
result.push(line)
30
start = end
31
lineLen = words[start].length
32
}
33
end++
34
}
35
36
let lastline = words[start]
37
for (let i = start + 1; i < end; i++) {
38
lastline += ' ' + words[i]
39
}
40
result.push(lastline.padEnd(maxWidth))
41
42
return result
43
};
Copied!
Template generated via Leetmark.

Problem:

Implement int sqrt(int x).
Compute and return the square root of x, where x is guaranteed to be a non-negative integer.
Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned.
Example 1:
1
Input: 4
2
Output: 2
Copied!
Example 2:
1
Input: 8
2
Output: 2
3
Explanation: The square root of 8 is 2.82842..., and since
4
the decimal part is truncated, 2 is returned.
Copied!

Solution:

Binary Search. The square root of x is within [0...(x+1)/2].
1
/**
2
* @param {number} x
3
* @return {number}
4
*/
5
let mySqrt = function(x) {
6
let max = Math.round(x / 2)
7
let min = 0
8
while (min <= max) {
9
const mid = Math.floor((min + max) / 2)
10
const diff = mid * mid - x
11
if (diff > 0) {
12
max = mid - 1
13
} else if (diff < 0) {
14
min = mid + 1
15
} else {
16
return mid
17
}
18
}
19
return max
20
};
Copied!
Template generated via Leetmark.

Problem:

Given an absolute path for a file (Unix-style), simplify it.
For example, path = "/home/", => "/home" path = "/a/./b/../../c/", => "/c"
Corner Cases:
  • Did you consider the case where path = "/../"? In this case, you should return "/".
  • Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". In this case, you should ignore redundant slashes and return "/home/foo".

Solution:

Use stack to handle /../.
ONE
RegExp matching.
1
/**
2
* @param {string} path
3
* @return {string}
4
*/
5
let simplifyPath = function(path) {
6
return '/' + (path.match(/[^\/]+/g) || [])
7
.reduce((stack, p) => {
8
if (p === '..') {
9
stack.pop()
10
} else if (p !== '.') {
11
stack.push(p)
12
}
13
return stack
14
}, [])
15
.join('/')
16
};
Copied!
TWO
Direct search.
1
/**
2
* @param {string} path
3
* @return {string}
4
*/
5
let simplifyPath = function(path) {
6
const len = path.length
7
const stack = []
8
let e = 0
9
while (e < len) {
10
while (e < len && path[e] === '/') {
11
e++
12
}
13
const s = e
14
while (e < len && path[e] !== '/') {
15
e++
16
}
17
if (s < e) {
18
const p = path.slice(s, e)
19
if (p === '..') {
20
stack.pop()
21
} else if (p !== '.') {
22
stack.push(p)
23
}
24
}
25
}
26
return '/' + stack.join('/')
27
};
Copied!
Template generated via Leetmark.

Problem:

Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.
You have the following 3 operations permitted on a word:
  1. 1.
    Insert a character
  2. 2.
    Delete a character
  3. 3.
    Replace a character
Example 1:
1
Input: word1 = "horse", word2 = "ros"
2
Output: 3
3
Explanation:
4
horse -> rorse (replace 'h' with 'r')
5
rorse -> rose (remove 'r')
6
rose -> ros (remove 'e')
Copied!
Example 2:
1
Input: word1 = "intention", word2 = "execution"
2
Output: 5
3
Explanation:
4
intention -> inention (remove 't')
5
inention -> enention (replace 'i' with 'e')
6
enention -> exention (replace 'n' with 'x')
7
exention -> exection (replace 'n' with 'c')
8
exection -> execution (insert 'u')
Copied!

Solution:

DP.
Define f(i, j) to be the min edit distance from word1[0...i) to word2[0...j).
1
f(0, 0) = 0
2
f(0, j) = f(0, j-1) + 1 // can only insert
3
f(i, 0) = f(i-1, 0) + 1 // can only delete
4
f(i, j) = min(
5
f(i, j-1) + 1 // insert
6
f(i-1, j) + 1 // delete
7
f(i-1, j-1) + (word1[i-1] !== word2[j-1] ? 1 : 0) // replace or do nothing
8
)
Copied!
1
/**
2
* @param {string} word1
3
* @param {string} word2
4
* @return {number}
5
*/
6
let minDistance = function(word1, word2) {
7
const len1 = word1.length
8
const len2 = word2.length
9
10
if(len1 <= 0 || len2 <= 0) {
11
return len1 + len2
12
}
13
14
const dp = []
15
16
for (let i = 0; i <= len1; i++) {
17
dp[i] = [i]
18
}
19
20
for (let j = 0; j <= len2; j++) {
21
dp[0][j] = j
22
}
23
24
for (let i = 1; i <= len1; i++) {
25
for (let j = 1; j <= len2; j++) {
26
dp[i][j] = Math.min(
27
dp[i][j-1] + 1,
28
dp[i-1][j] + 1,
29
dp[i-1][j-1] + (word1[i-1] === word2[j-1] ? 0 : 1)
30
)
31
}
32
}
33
34
return dp[len1][len2]
35
};
Copied!
Template generated via Leetmark.

Problem:

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in-place.
Example 1:
1
Input:
2
[
3
[1,1,1],
4
[1,0,1],
5
[1,1,1]
6
]
7
Output:
8
[
9
[1,0,1],
10
[0,0,0],
11
[1,0,1]
12
]
Copied!
Example 2:
1
Input:
2
[
3
[0,1,2,0],
4
[3,4,5,2],
5
[1,3,1,5]
6
]
7
Output:
8
[
9
[0,0,0,0],
10
[0,4,5,0],
11
[0,3,1,0]
12
]
Copied!
Follow up:
  • A straight forward solution using O(m**n) space is probably a bad idea.
  • A simple improvement uses O(m + n) space, but still not the best solution.
  • Could you devise a constant space solution?

Solution:

  • O(m**n) space solution: Copy a new matrix.
  • O(m + n) space solution: Use extra arrays to store rows and columns that need to be set 0.
  • Constant space solutions:
ONE
Instead of allocating extra arrays. Just use the first row and column.
First scan through the first row and column to see if they need be set 0. If so, mark and do it in the end.
Now scan the matrix and set 0 to the first row and column whenever a 0 is met.
Walk the matrix again and set 0 according to the first row and column.
Finally set the first row and column to 0 if needed.
1
/**
2
* @param {number[][]} matrix
3
* @return {void} Do not return anything, modify matrix in-place instead.
4
*/
5
let setZeroes = function(matrix) {
6
const height = matrix.length
7
if (height <= 0) { return }
8
const width = matrix[0].length
9
if (width <= 0) { return }
10
11
const shouldClearFirstRow = matrix[0].some(x => x === 0)
12
const shouldClearFirstCol = matrix.some(row => row[0] === 0)
13
14
for (let i = 1; i < height; i++) {
15
for (let j = 1; j < width; j++) {
16
if (matrix[i][j] === 0) {
17
matrix[i][0] = 0
18
matrix[0][j] = 0
19
}
20
}
21
}
22
23
for (let i = 1; i < height; i++) {
24
if (matrix[i][0] === 0) {
25
matrix[i].fill(0)
26
}
27
}
28
29
for (let j = 1; j < width; j++) {
30
if (matrix[0][j] === 0) {
31
for (let i = 1; i < height; i++) {
32
matrix[i][j] = 0
33
}
34
}
35
}
36
37
if (shouldClearFirstRow) {
38
matrix[0].fill(0)
39
}
40
41
if (shouldClearFirstCol) {
42
for (let i = 0; i < height; i++) {
43
matrix[i][0] = 0
44
}
45
}
46
};
Copied!
TWO
Use NaN to mark cells that need to be set 0.
Still constant space just a bit slower due to repeatedly setting overlapping NaNs.
1
/**
2
* @param {number[][]} matrix
3
* @return {void} Do not return anything, modify matrix in-place instead.
4
*/
5
let setZeroes = function(matrix) {
6
const height = matrix.length
7
if (height <= 0) { return }
8
const width = matrix[0].length
9
if (width <= 0) { return }
10
11
for (let i = 0; i < height; i++) {
12
for (let j = 0; j < width; j++) {
13
if (matrix[i][j] !== 0) { continue }
14
15
for (let jj = 0; jj < width; jj++) {
16
if (matrix[i][jj] !== 0) {
17
matrix[i][jj] = NaN
18
}
19
}
20
21
for (let ii = 0; ii < height; ii++) {
22
if (matrix[ii][j] !== 0) {
23
matrix[ii][j] = NaN
24
}
25
}
26
}
27
}
28
29
for (let i = 0; i < height; i++) {
30
for (let j = 0; j < width; j++) {
31
if (isNaN(matrix[i][j])) {
32
matrix[i][j] = 0
33
}
34
}
35
}
36
};
Copied!
Template generated via Leetmark.

Problem:

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.
Example 1:
1
Input:
2
matrix = [
3
[1, 3, 5, 7],
4
[10, 11, 16, 20],
5
[23, 30, 34, 50]
6
]
7
target = 3
8
Output: true
Copied!
Example 2:
1
Input:
2
matrix = [
3
[1, 3, 5, 7],
4
[10, 11, 16, 20],
5
[23, 30, 34, 50]
6
]
7
target = 13
8
Output: false
Copied!

Solution:

ONE
Search from top-left to bottom-right. O(n).
1
/**
2
* @param {number[][]} matrix
3
* @param {number} target
4
* @return {boolean}
5
*/
6
let searchMatrix = function(matrix, target) {
7
const height = matrix.length
8
if (height <= 0) { return false }
9
const width = matrix[0].length
10
if (width <= 0) { return false }
11
12
let i = 0
13
let j = width - 1
14
while (i < height && j >= 0) {
15
const diff = matrix[i][j] - target
16
if (diff > 0) {
17
j--
18
} else if (diff < 0) {
19
i++
20
} else {
21
return true
22
}
23
}
24
25
return false
26
};
Copied!
TWO
Binary search. O(logn).
View the matrix as an sorted array that is cut into n slices.
Take the algorithm from 35. Search Insert Position.
1
/**
2
* @param {number[][]} matrix
3
* @param {number} target
4
* @return {boolean}
5
*/
6
let searchMatrix = function(matrix, target) {
7
const height = matrix.length
8
if (height <= 0) { return false }
9
const width = matrix[0].length
10
if (width <= 0) { return false }
11
12
let s = 0
13
let e = width * height - 1
14
while (s <= e) {
15
const mid = Math.floor((s + e) / 2)
16
const diff = matrix[Math.floor(mid / width)][mid % width] - target
17
if (diff < 0) {
18
s = mid + 1
19
} else if (diff > 0) {
20
e = mid - 1
21
} else {
22
return true
23
}
24
}
25
26
return false
27
};
Copied!
Template generated via Leetmark.

Problem:

Given an array with n objects colored red, white or blue, sort them in-placeso that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note: You are not suppose to use the library's sort function for this problem.
Example:
1
Input: [2,0,2,1,1,0]
2
Output: [0,0,1,1,2,2]
Copied!
Follow up:
  • A rather straight forward solution is a two-pass algorithm using counting sort. First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.
  • Could you come up with a one-pass algorithm using only constant space?

Solution:

One-pass algorithm.
Take the idea of the partition algorithm from quick sort. Use 1 as pivot.
Count the number of sorted 0s and 2s so that we know where to swap.
1
/**
2
* @param {number[]} nums
3
* @return {void} Do not return anything, modify nums in-place instead.
4
*/
5
let sortColors = function(nums) {
6
const len = nums.length
7
let zeroEnd = 0
8
let twoStart = len - 1
9
let i = 0
10
while (i <= twoStart) {
11
if (nums[i] === 0 && i !== zeroEnd) {
12
const t = nums[i]
13
nums[i] = nums[zeroEnd]
14
nums[zeroEnd] = t
15
zeroEnd++
16
} else if (nums[i] === 2 && i !== twoStart) {
17
const t = nums[i]
18
nums[i] = nums[twoStart]
19
nums[twoStart] = t
20
twoStart--
21
} else {
22
i++
23
}
24
}
25
};
Copied!
Template generated via Leetmark.

Problem:

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
Example:
1
Input: n = 4, k = 2
2
Output:
3
[
4
[2,4],
5
[3,4],
6
[2,3],
7
[1,2],
8
[1,3],
9
[1,4],
10
]
Copied!

Solution:

Basic DFS + Backtracking.
1
/**
2
* @param {number} n
3
* @param {number} k
4
* @return {number[][]}
5
*/
6
let combine = function(n, k) {
7
const result = []
8
_combine(1, [], n, k, result)
9
return result
10
};
11
12
function _combine (cur, path, n, k, result) {
13
if (path.length === k) {
14
return result.push(path.slice())
15
}
16
17
while (cur <= n) {
18
path.push(cur)
19
_combine(++cur, path, n, k, result)
20
path.pop()
21
}
22
}
Copied!
Template generated via Leetmark.

Problem:

Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
1
Input: nums = [1,2,3]
2
Output:
3
[
4
[3],
5
[1],
6
[2],
7
[1,2,3],
8
[1,3],
9
[2,3],
10
[1,2],
11
[]
12
]
Copied!

Solution:

ONE
BFS.
1
/**
2
* @param {number[]} nums
3
* @return {number[][]}
4
*/
5
let subsets = function(nums) {
6
return nums.reduce((result, num) => result.concat(result.map(r => [...r, num])), [[]])
7
};
Copied!
Or more imperative. Loop backward to avoid crossing the boundary.
1
/**
2
* @param {number[]} nums
3
* @return {number[][]}
4
*/
5
let subsets = function(nums) {
6
const result = [[]]
7
for (let i = nums.length - 1; i >= 0; i--) {
8
for (let j = result.length - 1; j >= 0; j--) {
9
result.push([nums[i], ...result[j]])
10
}
11
}
12
return result
13
};
Copied!
TWO
DFS + Backtracking.
1
/**
2
* @param {number[]} nums
3
* @return {number[][]}
4
*/
5
let subsets = function(nums) {
6
const result = []
7
_subsets(nums, 0, [], result)
8
return result
9
};
10
11
function _subsets(nums, start, path, result) {
12
result.push(path.slice())
13
while (start < nums.length) {
14
path.push(nums[start])
15
_subsets(nums, ++start, path, result)
16
path.pop()
17
}
18
}
Copied!
Template generated via Leetmark.

Problem:

Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
Example:
1
board =
2
[
3
['A','B','C','E'],
4
['S','F','C','S'],
5
['A','D','E','E']
6
]
7
8
Given word = "ABCCED", return true.
9
Given word = "SEE", return true.
10
Given word = "ABCB", return false.
Copied!

Solution:

DFS + Backtracking. Replace the cell with NaN before proceeding to the next level and restore when backtracking.
1
/**
2
* @param {character[][]} board
3
* @param {string} word
4
* @return {boolean}
5
*/
6
let exist = function(board, word) {
7
const height = board.length
8
if (height <= 0) { return false }
9
const width = board[0].length
10
if (width <= 0) { return false }
11
12
for (let row = 0; row < height; row++) {
13
for (let col = 0; col < width; col++) {
14
if (board[row][col] === word[0] &&
15
_exist(board, word, 0, [[-1, 0], [1, 0], [0, -1], [0, 1]], row, col)
16
) {
17
return true
18
}
19
}
20
}
21
22
return false
23
};
24
25
function _exist (board, word, iWord, directions, row, col) {
26
if (iWord === word.length) {
27
return true
28
}
29
30
if (!board[row] || word[iWord] !== board[row][col]) {
31
return false
32
}
33
34
const cell = board[row][col]
35
board[row][col] = NaN
36
37
for (let i = directions.length - 1; i >= 0; i--) {
38
if (_exist(board, word, iWord+1, directions, row+directions[i][0], col+directions[i][1])) {
39
return true
40
}
41
}
42
43
board[row][col] = cell
44
45
return false
46
}
Copied!
Template generated via Leetmark.

Problem:

Given a sorted array nums, remove the duplicates in-place such that duplicates appeared at most twice and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Example 1:
1
Given nums = [1,1,1,2,2,3],
2
3
Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively.
4
5
It doesn't matter what you leave beyond the returned length.
Copied!
Example 2:
1
Given nums = [0,0,1,1,1,1,2,3,3],
2
3
Your function should return length = 7, with the first seven elements of nums being modified to 0, 0, 1, 1, 2, 3 and 3 respectively.
4
5
It doesn't matter what values are set beyond the returned length.
Copied!
Clarification:
Confused why the returned value is an integer but your answer is an array?
Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.
Internally you can think of this:
1
// nums is passed in by reference. (i.e., without making a copy)
2
int len = removeDuplicates(nums);
3
4
// any modification to nums in your function would be known by the caller.
5
// using the length returned by your function, it prints the first len elements.
6
for (int i = 0; i < len; i++) {
7
print(nums[i]);
8
}
Copied!

Solution:

1
/**
2
* @param {number[]} nums
3
* @return {number}
4
*/
5
let removeDuplicates = function(nums) {
6
let len = 0
7
for (let i = 0; i < nums.length; i++) {
8
if (nums[i] !== nums[len-2]) {
9
nums[len++] = nums[i]
10
}
11
}
12
return len
13
};
Copied!
Template generated via Leetmark.

Problem:

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).
You are given a target value to search. If found in the array return true, otherwise return false.
Example 1:
1
Input: nums = [2,5,6,0,0,1,2], target = 0
2
Output: true
Copied!
Example 2:
1
Input: nums = [2,5,6,0,0,1,2], target = 3
2
Output: false
Copied!
Follow up:
  • This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates.
  • Would this affect the run-time complexity? How and why?

Solution:

See 33. Search in Rotated Sorted Array. The code is basically the same. Except with duplicates we can not tell which way to jump when pivot == nums[e]. The only thing we can do is to ditch nums[e]. SO worst case O(*n*).
1
/**
2
* @param {number[]} nums
3
* @param {number} target
4
* @return {boolean}
5
*/
6
let search = function(nums, target) {
7
let s = 0
8
let e = nums.length - 1
9
10
while (s <= e) {
11
const p = (e + s) / 2 | 0
12
const pivot = nums[p]
13
14
if (target === pivot) {
15
return true
16
}
17
18
if (pivot < nums[e]) {
19
if (target > nums[p] && target <= nums[e]) {
20
s = p + 1
21
} else {
22
e = p - 1
23
}
24
} else if (pivot > nums[e]) {
25
if (target < nums[p] && target >= nums[s]) {
26
e = p - 1
27
} else {
28
s = p + 1
29
}
30
} else {
31
e--
32
}
33
}
34
35
return false
36
};
Copied!
Template generated via Leetmark.

Problem:

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
Example 1:
1
Input: 1->2->3->3->4->4->5
2
Output: 1->2->5
Copied!
Example 2:
1
Input: 1->1->1->2->3
2
Output: 2->3
Copied!

Solution:

p1 points to the current node. p points to the node before p1 so that we can ditch p1 if needed.
The list is sorted so we only need dupVal to keep the latest duplicate value.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @return {ListNode}
11
*/
12
let deleteDuplicates = function(head) {
13
if (!head) { return null }
14
const prehead = { next: head }
15
16
let p = prehead
17
let dupVal = NaN
18
19
for (let p1 = head; p1; p1 = p1.next) {
20
if (p1.val === dupVal) {
21
p.next = p1.next
22
} else if (p1.next && p1.val === p1.next.val) {
23
p.next = p1.next
24
dupVal = p1.val
25
} else {
26
p = p1
27
}
28
}
29
30
return prehead.next
31
};
Copied!
Template generated via Leetmark.

Problem:

Given a sorted linked list, delete all duplicates such that each element appear only once.
Example 1:
1
Input: 1->1->2
2
Output: 1->2
Copied!
Example 2:
1
Input: 1->1->2->3->3
2
Output: 1->2->3
Copied!

Solution:

ONE
Just like 82. Remove Duplicates from Sorted List II except keeping the first duplicate node.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @return {ListNode}
11
*/
12
let deleteDuplicates = function(head) {
13
if (!head) { return null }
14
const prehead = { next: head }
15
16
let p = prehead
17
let dupVal = NaN
18
19
for (let p1 = head; p1; p1 = p1.next) {
20
if (p1.val === dupVal) {
21
p.next = p1.next
22
} else {
23
if (p1.next && p1.val === p1.next.val) {
24
dupVal = p1.val
25
}
26
p = p1
27
}
28
}
29
30
return prehead.next
31
};
Copied!
TWO
Just compare the next node. This is way more faster.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @return {ListNode}
11
*/
12
let deleteDuplicates = function(head) {
13
if (!head) { return null }
14
15
let p = head
16
while (p) {
17
if (p.next && p.val === p.next.val) {
18
p.next = p.next.next
19
} else {
20
p = p.next
21
}
22
}
23
24
return head
25
};
Copied!
Template generated via Leetmark.

Problem:

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Could not load image
histogram.png
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].
Could not load image
histogram_area.png
The largest rectangle is shown in the shaded area, which has area = 10 unit.
Example:
1
Input: [2,1,5,6,2,3]
2
Output: 10
Copied!

Solution:

The height of a rectangle is determined by the lowest bar inside of it. So the core idea is, for each bar, assume it is the lowest bar and see how far it can expand. Then we have len(heights) rectangles. Return the max area.
For a bar b whose height is h, find the closest bar b1 on the left that is lower than h, and b2 on the right. The area of the rectangle is h * (i2 - i1 - 1).
Notice that if we just loop the bars from left to right, b1 and b2 of each bar may overlap.
index
height
width
area
i
heights[i]
i2 - i1 - 1
height * width
0
2
1 - -1 - 1
2
1
1
6 - -1 - 1
6
2
5
4 - 1 - 1
10
3
6
4 - 2 - 1
6
4
2
6 - 1 - 1
8
5
3
6 - 4 - 1
3
Observe how i1 and i2 changes depending on the height.
To reduce O(n^2) to O(n), we use a stack to store incremental bs. Because b1 and b2 are both lower than b, whenever we reach a bar that is lower than the top of the stack, we know it's a b2. So stack top is a b. Second top is a b1. Keep popping the b to calculate areas until b2 is no longer lower than stack top.
1
/**
2
* @param {number[]} heights
3
* @return {number}
4
*/
5
let largestRectangleArea = function(heights) {
6
const stack = [-1]
7
let max = 0
8
for (let i2 = 0; i2 <= heights.length; i2++) {
9
while ((heights[i2] || 0) < heights[stack[stack.length-1]]) {
10
const i = stack.pop()
11
const i1 = stack[stack.length-1]
12
max = Math.max(max, heights[i] * (i2 - i1 - 1))
13
}
14
stack.push(i2)
15
}
16
return max
17
};
18
Copied!
Template generated via Leetmark.

Problem:

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.
Example:
1
Input:
2
[
3
["1","0","1","0","0"],
4
["1","0","1","1","1"],
5
["1","1","1","1","1"],
6
["1","0","0","1","0"]
7
]
8
Output: 6
Copied!

Solution:

ONE
View every row as a base line then we just have to solve height(matrix) times the problem of 84. Largest Rectangle in Histogram.
1
/**
2
* @param {character[][]} matrix
3
* @return {number}
4
*/
5
let maximalRectangle = function(matrix) {
6
const height = matrix.length
7
if (height <= 0) { return 0 }
8
const width = matrix[0].length
9
if (width <= 0) { return 0 }
10
11
const heights = []
12
let max = 0
13
for (let row = 0; row < height; row++) {
14
for (let col = 0; col < width; col++) {
15
heights[col] = ((heights[col] || 0) + 1) * matrix[row][col]
16
}
17
max = Math.max(max, largestRectangleArea(heights))
18
}
19
20
return max
21
};
22
23
/**
24
* @param {number[]} heights
25
* @return {number}
26
*/
27
function largestRectangleArea (heights) {
28
const stack = [-1]
29
let max = 0
30
for (let i2 = 0; i2 <= heights.length; i2++) {
31
while ((heights[i2] || 0) < heights[stack[stack.length-1]]) {
32
const i = stack.pop()
33
const i1 = stack[stack.length-1]
34
max = Math.max(max, heights[i] * (i2 - i1 - 1))
35
}
36
stack.push(i2)
37
}
38
return max
39
};
Copied!
TWO
Same idea as above. Use DP to cache accumulated states.
Pick a pivot point (row, col) and assume it is on the base line. The adjoining 1s above (row, col) makes up the height of the rectangle. The width of the rectangle is determined by how many ajoining bars are taller than the pivot bar.
So for the rectangle whose bottom pivot is (row, col):
  • Define area(row, col) to be the area.
  • Define height(row, col) to be the height.
  • Define left(row, col) to be the col value of the bottom-left corner.
  • Define right(row, col) to be the col value of the bottom-right corner.
Also:
  • Define conLeft(row, col) to be the col value of the leftmost cell of the consecutive 1s on the left of (row, col).
  • Define conRight(row, col) to be the col value of the rightmost cell of the consecutive 1s on the right of (row, col).
With conLeft and conRight we can know if the rectangle on (row, col) shrinks comparing to (row-1, col).
1
if matrix[row][col] == 1
2
height(row, col) = height(row-1, col) + 1
3
4
// see how long this horizontal line can get
5
conLeft(row, col) = conLeft(row, col-1)
6
conRight(row, col) = conRight(row, col+1)
7
8
// width can only be shorter
9
left(row, col) = max( left(row-1, col), conLeft(row, col) )
10
right(row, col) = min( right(row-1, col), conRight(row, col) )
11
12
if matrix[row][col] == 0
13
height(row, col) = 0
14
conLeft(row, col) = col + 1
15
conRight(row, col) = col - 1
16
left(row, col) = 0 // back to leftmost position
17
right(row, col) = matrix.width // back to rightmost position
18
19
area(row, col) = (right(row, col) - left(row, col) + 1) * height(row, col)
Copied!
We only need to keep the last state. Use dynamic arrays to reduce space complexity.
1
/**
2
* @param {character[][]} matrix
3
* @return {number}
4
*/
5
let maximalRectangle = function(matrix) {
6
const height = matrix.length
7
if (height <= 0) { return 0 }
8
const width = matrix[0].length
9
if (width <= 0) { return 0 }
10
11
const heights = new Array(width).fill(0)
12
const lefts = new Array(width).fill(0)
13
const rights = new Array(width).fill(width)
14
15
let max = 0
16
17
for (let row = 0; row < height; row++) {
18
let conLeft = 0
19
let conRight = width - 1
20
for (let col = 0; col < width; col++) {
21
if (matrix[row][col] === '1') {
22
heights[col] = heights[col] + 1
23
lefts[col] = Math.max(lefts[col], conLeft)
24
} else {
25
heights[col] = 0
26
lefts[col] = 0
27
conLeft = col + 1
28
}
29
}
30
31
for (let col = width - 1; col >= 0; col--) {
32
if (matrix[row][col] === '1') {
33
rights[col] = Math.min(rights[col], conRight)
34
} else {
35
rights[col] = width
36
conRight = col - 1
37
}
38
}
39
40
for (let col = 0; col < width; col++) {
41
max = Math.max(max, (rights[col] - lefts[col] + 1) * heights[col])
42
}
43
}
44
45
return max
46
};
Copied!
Template generated via Leetmark.

Problem:

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
Example:
1
Input: head = 1->4->3->2->5->2, x = 3
2
Output: 1->2->2->4->3->5
Copied!

Solution:

Take the second part out as a new list and connect it back.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @param {number} x
11
* @return {ListNode}
12
*/
13
let partition = function(head, x) {
14
const prehead1 = { next: head }
15
let p1 = prehead1
16
let ptail1 = prehead1
17
18
const prehead2 = { next: null }
19
let p2 = prehead2
20
21
while (p1) {
22
const next = p1.next
23
if (next && next.val >= x) {
24
p1.next = next.next
25
p2.next = next
26
p2 = next
27
} else {
28
ptail1 = p1
29
p1 = p1.next
30
}
31
}
32
33
p2.next = null
34
ptail1.next = prehead2.next
35
36
return prehead1.next
37
};
Copied!
Template generated via Leetmark.

Problem:

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
Note:
  • The number of elements initialized in nums1 and nums2 are m and n respectively.
  • You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2.
Example:
1
Input:
2
nums1 = [1,2,3,0,0,0], m = 3
3
nums2 = [2,5,6], n = 3
4
5
Output: [1,2,2,3,5,6]
Copied!

Solution:

Loop backward and keep picking the larger one. nums1 is guaranteed longer than nums2 so just use n as boundary.
1
/**
2
* @param {number[]} nums1
3
* @param {number} m
4
* @param {number[]} nums2
5
* @param {number} n
6
* @return {void} Do not return anything, modify nums1 in-place instead.
7
*/
8
let merge = function(nums1, m, nums2, n) {
9
let len = (m--) + (n--)
10
while (n >= 0) {
11
nums1[--len] = nums1[m] >= nums2[n] ? nums1[m--] : nums2[n--]
12
}
13
};
Copied!
Template generated via Leetmark.

Problem:

The gray code is a binary numeral system where two successive values differ in only one bit.
Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.
Example 1:
1
Input: 2
2
Output: [0,1,3,2]
3
Explanation:
4
00 - 0
5
01 - 1
6
11 - 3
7
10 - 2
8
9
For a given n, a gray code sequence may not be uniquely defined.
10
For example, [0,2,3,1] is also a valid gray code sequence.
11
12
00 - 0
13
10 - 2
14
11 - 3
15
01 - 1
Copied!
Example 2:
1
Input: 0
2
Output: [0]
3
Explanation: We define the gray code sequence to begin with 0.
4
A gray code sequence of n has size = 2n, which for n = 0 the size is 20 = 1.
5
Therefore, for n = 0 the gray code sequence is [0].
Copied!

Solution:

1
0: [ 0 ]
2
1: [ 0, 1 ]
3
2: [ 00, 01, 11, 10 ]
4
3: [000, 001, 011, 010, 110, 111, 101, 100]
Copied!
The pattern is self-evident. Reverse the result set and prepend '1' to each item.
Use bitwise shift to speed up the calculation. It is unlikely to overflow since the result set is exponential.
1
/**
2
* @param {number} n
3
* @return {number[]}
4
*/
5
let grayCode = function(n) {
6
const result = [0]
7
for (let level = 0; level < n; level++) {
8
const prefix = 1 << level
9
for (let i = result.length - 1; i >= 0; i--) {
10
result.push(result[i] + prefix)
11
}
12
}
13
return result
14
};
Copied!
Template generated via Leetmark.

Problem:

Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
1
Input: [1,2,2]
2
Output:
3
[
4
[2],
5
[1],
6
[1,2,2],
7
[2,2],
8
[1,2],
9
[]
10
]
Copied!

Solution:

See 78. Subsets. Except:
  1. 1.
    Sort input to group duplicates.
  2. 2.
    Only consider each duplicate once, that is, when it is at the first slot.
1
/**
2
* @param {number[]} nums
3
* @return {number[][]}
4
*/
5
let subsetsWithDup = function(nums) {
6
const result = []
7
_subsetsWithDup(nums.sort(), 0, [], result)
8
return result
9
};
10
11
function _subsetsWithDup(nums, start, path, result) {
12
result.push(path.slice())
13
for (let i = start; i < nums.length; i++) {
14
if(i > start && nums[i] === nums[i-1]) {
15
continue
16
}
17
path.push(nums[i])
18
_subsetsWithDup(nums, i + 1, path, result)
19
path.pop()
20
}
21
}
Copied!
Template generated via Leetmark.

Problem:

A message containing letters from A-Z is being encoded to numbers using the following mapping:
1
'A' -> 1
2
'B' -> 2
3
...
4
'Z' -> 26
Copied!
Given a non-empty string containing only digits, determine the total number of ways to decode it.
Example 1:
1
Input: "12"
2
Output: 2
3
Explanation: It could be decoded as "AB" (1 2) or "L" (12).
Copied!
Example 2:
1
Input: "226"
2
Output: 3
3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
Copied!

Solution:

Define f(i) to be the number of ways to decode s[0...i].
Note that there could be '0'.
1
f(0) = 1, if s[i] !== '0'
2
f(i) = 0, if s.length <= 0 || s[i] === '0'
3
f(i) = f(i-1), if i > 0 && s[i] !== '0'
4
+
5
f(i-2), if i > 0 && s[i-1] !== '0' && s[i-1] * 10 + s[i] <= 26
Copied!
Only need to store the last two states. Init f(-1) = 1 for easy calculation.
1
/**
2
* @param {string} s
3
* @return {number}
4
*/
5
let numDecodings = function(s) {
6
let dp = s[0] > 0 ? 1 : 0
7
let dp_1 = dp
8
let dp_2 = 1
9
10
for (let i = 1; i < s.length; i++) {
11
dp = 0
12
if (s[i] !== '0') {
13
dp += dp_1
14
}
15
if (s[i-1] !== '0' && s[i-1] + s[i] <= 26) {
16
dp += dp_2
17
}
18
dp_2 = dp_1
19
dp_1 = dp
20
}
21
22
return dp
23
};
Copied!
Template generated via Leetmark.

Problem:

Reverse a linked list from position m to n. Do it in one-pass.
**Note:**1 ≤ mn ≤ length of list.
Example:
1
Input: 1->2->3->4->5->NULL, m = 2, n = 4
2
Output: 1->4->3->2->5->NULL
Copied!

Solution:

Break the list into 3 parts.
1
/**
2
* Definition for singly-linked list.
3
* function ListNode(val) {
4
* this.val = val;
5
* this.next = null;
6
* }
7
*/
8
/**
9
* @param {ListNode} head
10
* @param {number} m
11
* @param {number} n
12
* @return {ListNode}
13
*/
14
let reverseBetween = function(head, m, n) {
15
if (m === n) { return head }
16
17
const prehead = { next: head }
18
n = n - m
19
20
let l1tail = prehead
21
while (--m > 0) {
22
l1tail = l1tail.next
23
}
24
25
let l2prehead = l1tail
26
let l2head = l2prehead.next
27
let l2tail = l2head
28
while (n-- > 0) {
29
const next = l2head.next
30
l2head.next = l2prehead
31
l2prehead = l2head
32
l2head = next
33
}
34
35
l2tail.next = l2head.next // l3head
36
l2head.next = l2prehead
37
l1tail.next = l2head
38
39
return prehead.next
40
};
Copied!
Template generated via Leetmark.

Problem:

Given a string containing only digits, restore it by returning all possible valid IP address combinations.
Example:
1
Input: "25525511135"
2
Output: ["255.255.11.135", "255.255.111.35"]
Copied!

Solution:

Backtracking. Note that leading '0' is not allowed except just '0'.
1
/**
2
* @param {string} s
3
* @return {string[]}
4
*/
5
let restoreIpAddresses = function(s, i = 0, path = [], result = []) {
6
if (i === s.length) {
7
if (path.length === 4) {
8
result.push(path.join('.'))
9
}
10
return result
11
}
12
13
const digit = s.charCodeAt(i) - 48
14
15
if (i === 0) {
16
path[0] = digit
17
restoreIpAddresses(s, i + 1, path, result)
18
path[0] = 0
19
return result
20
}
21
22
const sum = path[path.length - 1] * 10 + digit
23
24
if (digit < sum && sum <= 255) {
25
path[path.length - 1] = sum
26
restoreIpAddresses(s, i + 1, path, result)
27
path[path.length - 1] = (sum - digit) / 10
28
}
29
30
if (path.length < 4) {
31
path.push(digit)
32
restoreIpAddresses(s, i + 1, path, result)
33
path.pop()
34
}
35
36
return result
37
};
Copied!
Template generated via Leetmark.

Problem:

Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
Example 1:
1
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
2
Output: true
Copied!
Example 2:
1
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
2
Output: false
Copied!

Solution:

Define f(i, j) to be whether s3[0...i+j-1) can be formed by the interleaving of s1[0...i) and s2[0...j).
1
f(i, j) = true, i <= 0 || j <= 0 // meaningless, skipped
2
f(i, j) = f(i-1, j) && s1[i-1] == s3[i+j-1] || f(i, j-1) && s2[j-1] == s3[i+j-1], 0 < i <= len(s1), 0 < j <= len(s2)
Copied!
Dynamic array can be used.
1
/**
2
* @param {string} s1
3
* @param {string} s2
4
* @param {string} s3
5
* @return {boolean}
6
*/
7
let isInterleave = function(s1, s2, s3) {
8
const len1 = s1.length
9
const len2 = s2.length
10
const len3 = s3.length
11
if (len1 + len2 !== len3) { return false }
12
if (len1 <= 0) { return s2 === s3 }
13
if (len2 <= 0) { return s1 === s3 }
14
15
const dp = []
16
for (let i = 0; i <= len1; i++) {
17
for (let j = 0; j <= len2; j++) {
18
dp[j] = (i <= 0 || dp[j]) && s1[i-1] === s3[i+j-1] ||
19
(j <= 0 || dp[j-1]) && s2[j-1] === s3[i+j-1]
20
}
21
}
22
return dp[len2]
23
};
Copied!
Template generated via Leetmark.

Problem:

Given two binary trees, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical and the nodes have the same value.
Example 1:
1
Input: 1 1
2
/ \ / \
3
2 3 2 3
4
5
[1,2,3], [1,2,3]
6
7
Output: true
Copied!
Example 2:
1
Input: 1 1
2
/ \
3
2 2
4
5
[1,2], [1,null,2]
6
7
Output: false
Copied!
Example 3:
1
Input: 1 1
2
/ \ / \
3
2 1 1 2
4
5
[1,2,1], [1,1,2]
6
7
Output: false
Copied!

Solution:

The code should be self-evident.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} p
10
* @param {TreeNode} q
11
* @return {boolean}
12
*/
13
let isSameTree = function(p, q) {
14
return p === null && q === null ||
15
p !== null && q !== null && p.val === q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
16
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
For example, this binary tree [1,2,2,3,4,4,3] is symmetric:
1
1
2
/ \
3
2 2
4
/ \ / \
5
3 4 4 3
Copied!
But the following [1,2,2,null,3,null,3] is not:
1
1
2
/ \
3
2 2
4
\ \
5
3 3
Copied!
Note: Bonus points if you could solve it both recursively and iteratively.

Solution:

ONE
The result of pre-order and post-order traversal on a symmetric tree should be the same.
So just like 100. Same Tree. Except one is pre-order traversal and the other is post-order.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {boolean}
11
*/
12
let isSymmetric = function(root) {
13
return root === null || isSymmetricTree(root.left, root.right)
14
};
15
16
/**
17
* @param {TreeNode} p
18
* @param {TreeNode} q
19
* @return {boolean}
20
*/
21
function isSymmetricTree (p, q) {
22
return p === null && q === null ||
23
p !== null && q !== null && p.val === q.val && isSymmetricTree(p.left, q.right) && isSymmetricTree(p.right, q.left)
24
};
Copied!
TWO
Level order traversal. Check symmetry before entering the next level.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {boolean}
11
*/
12
let isSymmetric = function(root) {
13
if (root === null) { return true }
14
15
const queue = [NaN, root]
16
17
while (queue.length > 1) {
18
const node = queue.shift()
19
if (node !== node) {
20
for (let i = 0, j = queue.length-1; i <= j; i++, j--) {
21
if (queue[i] === null && queue[j] !== null ||
22
queue[i] !== null && queue[j] === null ||
23
queue[i] !== null && queue[j] !== null && queue[i].val !== queue[j].val
24
) {
25
return false
26
}
27
}
28
queue.push(NaN)
29
} else {
30
if (node !== null) {
31
queue.push(node.left)
32
queue.push(node.right)
33
}
34
}
35
}
36
37
return true
38
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
For example: Given binary tree [3,9,20,null,null,15,7],
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!
return its level order traversal as:
1
[
2
[3],
3
[9,20],
4
[15,7]
5
]
Copied!

Solution:

The code should be self-evident.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number[][]}
11
*/
12
let levelOrder = function(root) {
13
if (!root) { return [] }
14
15
const result = []
16
const queue = [NaN, root]
17
while (queue.length > 1) {
18
const node = queue.shift()
19
if (node !== node) {
20
result.push(queue.map(n => n.val))
21
queue.push(NaN)
22
} else {
23
if (node.left) { queue.push(node.left) }
24
if (node.right) { queue.push(node.right) }
25
}
26
}
27
28
return result
29
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
For example: Given binary tree [3,9,20,null,null,15,7],
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!
return its zigzag level order traversal as:
1
[
2
[3],
3
[20,9],
4
[15,7]
5
]
Copied!

Solution:

Reverse the level when pushing to the reuslt.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number[][]}
11
*/
12
let zigzagLevelOrder = function(root) {
13
if (!root) { return [] }
14
15
const result = []
16
const queue = [NaN, root]
17
let zipzag = false
18
while (queue.length > 1) {
19
const node = queue.shift()
20
if (node !== node) {
21
if (zipzag = !zipzag) {
22
result.push(queue.map(n => n.val))
23
} else {
24
result.push(queue.map(n => n.val).reverse())
25
}
26
queue.push(NaN)
27
} else {
28
if (node.left) { queue.push(node.left) }
29
if (node.right) { queue.push(node.right) }
30
}
31
}
32
33
return result
34
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Note: A leaf is a node with no children.
Example:
Given binary tree [3,9,20,null,null,15,7],
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!
return its depth = 3.

Solution:

The code should be self-evident.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number}
11
*/
12
let maxDepth = function(root) {
13
return root === null
14
? 0
15
: Math.max(maxDepth(root.left), maxDepth(root.right)) + 1
16
};
Copied!
Template generated via Leetmark.

Problem:

Given preorder and inorder traversal of a tree, construct the binary tree.
Note: You may assume that duplicates do not exist in the tree.
For example, given
1
preorder = [3,9,20,15,7]
2
inorder = [9,3,15,20,7]
Copied!
Return the following binary tree:
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!

Solution:

Pattern of preorder traversal result: pre(root) = root + pre(root.left) + pre(root.right)
Pattern of inorder traversal result: in(root) = in(root.left) + root + in(root.right)
There are no duplicates so get the first item in preorder result, pinpoint it in inorder result. Then we know the size of left and right subtree.
Repeat the process on subtrees.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {number[]} preorder
10
* @param {number[]} inorder
11
* @return {TreeNode}
12
*/
13
let buildTree = function(preorder, inorder) {
14
return _buildTree(preorder, inorder, 0, preorder.length, 0, inorder.length)
15
};
16
17
function _buildTree (preorder, inorder, pStart, pEnd, iStart, iEnd) {
18
if (pStart >= pEnd || iStart >= iEnd) {
19
return null
20
}
21
const val = preorder[pStart]
22
const node = new TreeNode(val)
23
for (let i = iStart; i < iEnd; i++) {
24
if (val === inorder[i]) {
25
node.left = _buildTree(preorder, inorder, pStart + 1, i - iStart + (pStart + 1), iStart, i)
26
node.right = _buildTree(preorder, inorder, (i + 1) - iEnd + pEnd, pEnd, i + 1, iEnd)
27
break
28
}
29
}
30
return node
31
}
Copied!
Template generated via Leetmark.

Problem:

Given inorder and postorder traversal of a tree, construct the binary tree.
Note: You may assume that duplicates do not exist in the tree.
For example, given
1
inorder = [9,3,15,20,7]
2
postorder = [9,15,7,20,3]
Copied!
Return the following binary tree:
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!

Solution:

Pattern of inorder traversal result: in(root) = in(root.left) + root + in(root.right)
Pattern of postorder traversal result: post(root) = post(root.left) + post(root.right) + root
There are no duplicates so get the first item in preorder result, pinpoint it in inorder result. Then we know the size of left and right subtree.
Repeat the process on subtrees.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {number[]} inorder
10
* @param {number[]} postorder
11
* @return {TreeNode}
12
*/
13
let buildTree = function(inorder, postorder) {
14
return _buildTree(postorder, inorder, 0, postorder.length, 0, inorder.length)
15
};
16
17
function _buildTree (postorder, inorder, pStart, pEnd, iStart, iEnd) {
18
if (pStart >= pEnd || iStart >= iEnd) {
19
return null
20
}
21
const val = postorder[pEnd - 1]
22
const node = new TreeNode(val)
23
for (let i = iStart; i < iEnd; i++) {
24
if (val === inorder[i]) {
25
node.left = _buildTree(postorder, inorder, pStart, i - iStart + pStart, iStart, i)
26
node.right = _buildTree(postorder, inorder, (i + 1) - iEnd + (pEnd - 1), pEnd - 1, i + 1, iEnd)
27
break
28
}
29
}
30
return node
31
}
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).
For example: Given binary tree [3,9,20,null,null,15,7],
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!
return its bottom-up level order traversal as:
1
[
2
[15,7],
3
[9,20],
4
[3]
5
]
Copied!

Solution:

1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number[][]}
11
*/
12
let levelOrderBottom = function(root) {
13
if (!root) { return [] }
14
15
const result = []
16
const queue = [NaN, root]
17
while (queue.length > 1) {
18
const node = queue.shift()
19
if (node !== node) {
20
result.unshift(queue.map(n => n.val))
21
queue.push(NaN)
22
} else {
23
if (node.left) { queue.push(node.left) }
24
if (node.right) { queue.push(node.right) }
25
}
26
}
27
28
return result
29
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as:
a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
Example 1:
Given the following tree [3,9,20,null,null,15,7]:
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!
Return true.
Example 2:
Given the following tree [1,2,2,3,3,null,null,4,4]:
1
1
2
/ \
3
2 2
4
/ \
5
3 3
6
/ \
7
4 4
Copied!
Return false.

Solution:

Get the depth of subtrees and compare. Prune the DFS tree by returning -1.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {boolean}
11
*/
12
let isBalanced = function(root) {
13
return getDepth(root) >= 0
14
};
15
16
function getDepth (root) {
17
if (!root) { return 0 }
18
const leftDepth = getDepth(root.left)
19
if (leftDepth < 0) { return -1 }
20
const rightDepth = getDepth(root.right)
21
if (rightDepth < 0) { return -1 }
22
return Math.abs(leftDepth - rightDepth) <= 1 ? Math.max(leftDepth, rightDepth) + 1 : -1
23
}
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
Note: A leaf is a node with no children.
Example:
Given binary tree [3,9,20,null,null,15,7],
1
3
2
/ \
3
9 20
4
/ \
5
15 7
Copied!
return its minimum depth = 2.

Solution:

Ignore null children.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number}
11
*/
12
let minDepth = function(root) {
13
if (!root) { return 0 }
14
if (root.left !== null && root.right !== null) {
15
return Math.min(minDepth(root.left), minDepth(root.right)) + 1
16
} else if (root.left !== null) {
17
return minDepth(root.left) + 1
18
} else {
19
return minDepth(root.right) + 1
20
}
21
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
Note: A leaf is a node with no children.
Example:
Given the below binary tree and sum = 22,
1
5
2
/ \
3
4 8
4
/ / \
5
11 13 4
6
/ \ \
7
7 2 1
Copied!
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

Solution:

Note that node value could be negative so pruning can not be performed.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @param {number} sum
11
* @return {boolean}
12
*/
13
let hasPathSum = function(root, sum) {
14
if (!root) { return false }
15
if (root.left === null && root.right === null) { return root.val === sum }
16
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val)
17
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.
Note: A leaf is a node with no children.
Example:
Given the below binary tree and sum = 22,
1
5
2
/ \
3
4 8
4
/ / \
5
11 13 4
6
/ \ / \
7
7 2 5 1
Copied!
Return:
1
[
2
[5,4,11,2],
3
[5,8,4,5]
4
]
Copied!

Solution:

Simple backtracking.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @param {number} sum
11
* @return {number[][]}
12
*/
13
let pathSum = function(root, sum, path = [], result = []) {
14
if (!root) { return result }
15
16
if (root.left === null && root.right === null) {
17
if (root.val === sum) {
18
result.push([...path, root.val])
19
}
20
return result
21
}
22
23
path.push(root.val)
24
pathSum(root.left, sum - root.val, path, result)
25
pathSum(root.right, sum - root.val, path, result)
26
path.pop()
27
28
return result
29
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree, flatten it to a linked list in-place.
For example, given the following tree:
1
1
2
/ \
3
2 5
4
/ \ \
5
3 4 6
Copied!
The flattened tree should look like:
1
1
2
\
3
2
4
\
5
3
6
\
7
4
8
\
9
5
10
\
11
6
Copied!

Solution:

Return the leaf node of a flattened subtree for concatenation.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {void} Do not return anything, modify root in-place instead.
11
*/
12
let flatten = function(root) {
13
_flatten(root)
14
};
15
16
/**
17
* @param {TreeNode} root
18
* @return {TreeNode} leaf node of a flattened subtree
19
*/
20
function _flatten (root) {
21
if (!root) { return null }
22
const leftLeaf = _flatten(root.left)
23
const rightLeaf = _flatten(root.right)
24
if (leftLeaf !== null) {
25
leftLeaf.right = root.right
26
root.right = root.left
27
} else if (rightLeaf === null) {
28
return root
29
}
30
31
root.left = null
32
return rightLeaf || leftLeaf
33
}
Copied!
Template generated via Leetmark.

Problem:

Given a string S and a string T, count the number of distinct subsequences of S which equals T.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).
Example 1:
1
Input: S = "rabbbit", T = "rabbit"
2
Output: 3
3
Explanation:
4
5
As shown below, there are 3 ways you can generate "rabbit" from S.
6
(The caret symbol ^ means the chosen letters)
7
8
rabbbit
9
^^^^ ^^
10
rabbbit
11
^^ ^^^^
12
rabbbit
13
^^^ ^^^
Copied!
Example 2:
1
Input: S = "babgbag", T = "bag"
2
Output: 5
3
Explanation:
4
5
As shown below, there are 5 ways you can generate "bag" from S.
6
(The caret symbol ^ means the chosen letters)
7
8
babgbag
9
^^ ^
10
babgbag
11
^^ ^
12
babgbag
13
^ ^^
14
babgbag
15
^ ^^
16
babgbag
17
^^^
Copied!

Solution:

Define f(i, j) to be the number of ways that generate T[0...j) from S[0...i).
For f(i, j) you can always skip S[i-1], but can only take it when S[i-1] === T[j-1].
1
f(0, j) = 0, j > 0 // nothing to delete
2
f(i, 0) = 1 // delete all
3
f(i, j) = f(i-1, j) + (S[i-1] === T[j-1] ? f(i-1, j-1) : 0)
Copied!
Dynamic array can be used.
1
/**
2
* @param {string} s
3
* @param {string} t
4
* @return {number}
5
*/
6
let numDistinct = function(s, t) {
7
const lens = s.length
8
const lent = t.length
9
const dp = new Array(lent + 1).fill(0)
10
dp[0] = 1
11
for (let i = 1; i <= lens; i++) {
12
for (let j = lent; j >= 1; j--) {
13
if (s[i-1] === t[j-1]) {
14
dp[j] += dp[j-1]
15
}
16
}
17
}
18
return dp[lent]
19
};
20
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree
1
struct TreeLinkNode {
2
TreeLinkNode *left;
3
TreeLinkNode *right;
4
TreeLinkNode *next;
5
}
6
Copied!
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.
Initially, all next pointers are set to NULL.
Note:
  • You may only use constant extra space.
  • Recursive approach is fine, implicit stack space does not count as extra space for this problem.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).
Example:
Given the following perfect binary tree,
1
1
2
/ \
3
2 3
4
/ \ / \
5
4 5 6 7
6
Copied!
After calling your function, the tree should look like:
1
1 -> NULL
2
/ \
3
2 -> 3 -> NULL
4
/ \ / \
5
4->5->6->7 -> NULL
6
Copied!

Solution:

ONE
Recursive.
For every node:
  • Left child: points to node.right.
  • Right child: points to node.next.left if node.next exists.
1
/**
2
* Definition for binary tree with next pointer.
3
* function TreeLinkNode(val) {
4
* this.val = val;
5
* this.left = this.right = this.next = null;
6
* }
7
*/
8
9
/**
10
* @param {TreeLinkNode} root
11
* @return {void} Do not return anything, modify tree in-place instead.
12
*/
13
let connect = function(root) {
14
if (!root) { return }
15
if (root.left !== null) {
16
root.left.next = root.right
17
connect(root.left)
18
}
19
if (root.right !== null) {
20
if (root.next !== null) {
21
root.right.next = root.next.left
22
}
23
connect(root.right)
24
}
25
};
Copied!
TWO
Level order traversal.
1
/**
2
* Definition for binary tree with next pointer.
3
* function TreeLinkNode(val) {
4
* this.val = val;
5
* this.left = this.right = this.next = null;
6
* }
7
*/
8
9
/**
10
* @param {TreeLinkNode} root
11
* @return {void} Do not return anything, modify tree in-place instead.
12
*/
13
let connect = function(root) {
14
if (!root) { return }
15
16
const queue = [NaN, root]
17
while (queue.length > 1) {
18
const node = queue.shift()
19
if (node !== node) {
20
for (let i = 0; i < queue.length; i++) {
21
queue[i].next = queue[i+1] || null
22
}
23
queue.push(NaN)
24
} else {
25
if (node.left !== null) { queue.push(node.left) }
26
if (node.right !== null) { queue.push(node.right) }
27
}
28
}
29
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree
1
struct TreeLinkNode {
2
TreeLinkNode *left;
3
TreeLinkNode *right;
4
TreeLinkNode *next;
5
}
6
Copied!
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.
Initially, all next pointers are set to NULL.
Note:
  • You may only use constant extra space.
  • Recursive approach is fine, implicit stack space does not count as extra space for this problem.
Example:
Given the following binary tree,
1
1
2
/ \
3
2 3
4
/ \ \
5
4 5 7
6
Copied!
After calling your function, the tree should look like:
1
1 -> NULL
2
/ \
3
2 -> 3 -> NULL
4
/ \ \
5
4-> 5 -> 7 -> NULL
6
Copied!

Solution:

ONE
The tree may not be perfect now. So keep finding next until there is a node with children, or null.
This also means post-order traversal is required.
1
/**
2
* Definition for binary tree with next pointer.
3
* function TreeLinkNode(val) {
4
* this.val = val;
5
* this.left = this.right = this.next = null;
6
* }
7
*/
8
9
/**
10
* @param {TreeLinkNode} root
11
* @return {void} Do not return anything, modify tree in-place instead.
12
*/
13
let connect = function(root) {
14
if (!root) { return }
15
let next = null
16
for (let node = root.next; node !== null; node = node.next) {
17
if (node.left !== null) {
18
next = node.left
19
break
20
}
21
if (node.right !== null) {
22
next = node.right
23
break
24
}
25
}
26
if (root.right !== null) {
27
root.right.next = next
28
}
29
if (root.left !== null) {
30
root.left.next = root.right || next
31
}
32
connect(root.right)
33
connect(root.left)
34
};
Copied!
TWO
Level order traversal. Exact same as 116. Populating Next Right Pointers in Each Node.
1
/**
2
* Definition for binary tree with next pointer.
3
* function TreeLinkNode(val) {
4
* this.val = val;
5
* this.left = this.right = this.next = null;
6
* }
7
*/
8
9
/**
10
* @param {TreeLinkNode} root
11
* @return {void} Do not return anything, modify tree in-place instead.
12
*/
13
let connect = function(root) {
14
if (!root) { return }
15
16
const queue = [NaN, root]
17
while (queue.length > 1) {
18
const node = queue.shift()
19
if (node !== node) {
20
for (let i = 0; i < queue.length; i++) {
21
queue[i].next = queue[i+1] || null
22
}
23
queue.push(NaN)
24
} else {
25
if (node.left !== null) { queue.push(node.left) }
26
if (node.right !== null) { queue.push(node.right) }
27
}
28
}
29
};
Copied!
Template generated via Leetmark.

Problem:

Given a non-negative integer numRows, generate the first numRows of Pascal's triangle.
Could not load image
PascalTriangleAnimated2.gif
In Pascal's triangle, each number is the sum of the two numbers directly above it.
Example:
1
Input: 5
2
Output:
3
[
4
[1],
5
[1,1],
6
[1,2,1],
7
[1,3,3,1],
8
[1,4,6,4,1]
9
]
10
Copied!

Solution:

Dynamic Programming 101.
1
/**
2
* @param {number} numRows
3
* @return {number[][]}
4
*/
5
let generate = function(numRows) {
6
if (numRows <= 0) { return [] }
7
8
const result = [[1]]
9
for (let i = 1; i < numRows; i++) {
10
const lastRow = result[i-1]
11
const row = [1]
12
for (let j = 1; j < i; j++) {
13
row[j] = lastRow[j] + lastRow[j-1]
14
}
15
row.push(1)
16
result.push(row)
17
}
18
19
return result
20
};
Copied!
Template generated via Leetmark.

Problem:

Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal's triangle.
Note that the row index starts from 0.
Could not load image
PascalTriangleAnimated2.gif
In Pascal's triangle, each number is the sum of the two numbers directly above it.
Example:
1
Input: 3
2
Output: [1,3,3,1]
3
Copied!
Follow up:
Could you optimize your algorithm to use only O(k) extra space?

Solution:

Dynamic Programming 101 with dynamic array.
State (i, j) depends on (i-1, j) and (i-1, j-1). So to access (i-1, j-1) iteration must be from right to left.
1
/**
2
* @param {number} rowIndex
3
* @return {number[]}
4
*/
5
let getRow = function(rowIndex) {
6
if (rowIndex < 0) { return [] }
7
8
const row = [1]
9
for (let i = 1; i <= rowIndex; i++) {
10
for (let j = i - 1; j > 0; j--) {
11
row[j] += row[j-1]
12
}
13
row.push(1)
14
}
15
16
return row
17
};
Copied!
Template generated via Leetmark.

Problem:

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
1
[
2
[2],
3
[3,4],
4
[6,5,7],
5
[4,1,8,3]
6
]
7
Copied!
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.

Solution:

Define f(i, j) to be the minimum path sum from triangle[0][0] to triangle[i][j].
1
f(i, 0) = f(i-1, j) + triangle[i][0]
2
f(i, j) = min( f(i-1, j-1), f(i-1, j) ) + triangle[i][j], 0 < j < i
3
f(i, i) = f(i-1, i-1) + triangle[i][i], i > 0
Copied!
Dynamic array can be used.
1
/**
2
* @param {number[][]} triangle
3
* @return {number}
4
*/
5
let minimumTotal = function(triangle) {
6
if (triangle.length <= 0) { return 0 }
7
8
const dp = [triangle[0][0]]
9
for (let i = 1; i < triangle.length; i++) {
10
dp[i] = dp[i-1] + triangle[i][i]
11
for (let j = i - 1; j >= 1; j--) {
12
dp[j] = Math.min(dp[j], dp[j-1]) + triangle[i][j]
13
}
14
dp[0] += triangle[i][0]
15
}
16
return Math.min(...dp)
17
};
Copied!
Template generated via Leetmark.

Problem:

Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.
Note that you cannot sell a stock before you buy one.
Example 1:
1
Input: [7,1,5,3,6,4]
2
Output: 5
3
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
4
Not 7-1 = 6, as selling price needs to be larger than buying price.
5
Copied!
Example 2:
1
Input: [7,6,4,3,1]
2
Output: 0
3
Explanation: In this case, no transaction is done, i.e. max profit = 0.
4
Copied!

Solution:

Only care about positive profits. Take the frist item as base and scan to the right. If we encounter an item j whose price price[j] is lower than the base (which means if we sell now the profit would be negative), we sell j-1 instead and make j the new base.
Because price[j] is lower that the base, using j as new base is guaranteed to gain more profit comparing to the old one.
1
/**
2
* @param {number[]} prices
3
* @return {number}
4
*/
5
let maxProfit = function(prices) {
6
let max = 0
7
let base = prices[0]
8
for (let i = 1; i < prices.length; i++) {
9
const profit = prices[i] - base
10
if (profit > max) {
11
max = profit
12
} else if (profit < 0) {
13
base = prices[i]
14
}
15
}
16
return max
17
};
Copied!
Template generated via Leetmark.

Problem:

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).
Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
Example 1:
1
Input: [7,1,5,3,6,4]
2
Output: 7
3
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
4
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
5
Copied!
Example 2:
1
Input: [1,2,3,4,5]
2
Output: 4
3
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
4
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
5
engaging multiple transactions at the same time. You must sell before buying again.
6
Copied!
Example 3:
1
Input: [7,6,4,3,1]
2
Output: 0
3
Explanation: In this case, no transaction is done, i.e. max profit = 0.
Copied!

Solution:

Sell immediately after the price drops. Or in other perspective, it is the sum of all the incremental pairs (buy in then immediately sell out).
1
/**
2
* @param {number[]} prices
3
* @return {number}
4
*/
5
let maxProfit = function(prices) {
6
let max = 0
7
for (let i = 1; i < prices.length; i++) {
8
if (prices[i] > prices[i-1]) {
9
max += prices[i] - prices[i-1]
10
}
11
}
12
return max
13
};
Copied!
Template generated via Leetmark.

Problem:

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most two transactions.
**Note:**You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
Example 1:
1
Input: [3,3,5,0,0,3,1,4]
2
Output: 6
3
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
4
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.
Copied!
Example 2:
1
Input: [1,2,3,4,5]
2
Output: 4
3
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
4
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
5
engaging multiple transactions at the same time. You must sell before buying again.
6
Copied!
Example 3:
1
Input: [7,6,4,3,1]
2
Output: 0
3
Explanation: In this case, no transaction is done, i.e. max profit = 0.
Copied!

Solution:

Multiple transactions may not be engaged in at the same time. That means if we view the days that involed in the same transaction as a group, there won't be any intersection. We may complete at most two transactions, so divide the days into two groups, [0...k] and [k...n-1]. Notice k exists in both groups because technically we can sell out then immediately buy in at the same day.
Define p1(i) to be the max profit of day [0...i]. This is just like the problem of 121. Best Time to Buy and Sell Stock.
1
p1(0) = 0
2
p1(i) = max( p1(i-1), prices[i] - min(prices[0], ..., prices[i-1]) ), 0 < i <= n-1
Copied!
Define p2(i) to be the max profit of day [i...n-1]. This is the mirror of p1.
1
p2(n-1) = 0
2
p2(i) = max( p2(i+1), max(prices[i], ..., prices[n-1]) - prices[i] ), n-1 > i >= 0
Copied!
Define f(k) to be p1(k) + p2(k). We need to get max( f(0), ..., f(n-1) ).
1
/**
2
* @param {number[]} prices
3
* @return {number}
4
*/
5
let maxProfit = function(prices) {
6
const len = prices.length
7
if (len <= 1) { return 0 }
8
9
const dp = [0]
10
11
let min = prices[0]
12
for (let i = 1; i < len; i++) {
13
dp[i] = Math.max(dp[i-1], prices[i] - min)
14
min = Math.min(prices[i], min)
15
}
16
17
let p2 = 0
18
let max = prices[len-1]
19
for (let i = len-2; i >= 0; i--) {
20
max = Math.max(prices[i], max)
21
p2 = Math.max(p2, max - prices[i])
22
dp[i] += p2
23
}
24
25
return Math.max(...dp)
26
};
Copied!
Template generated via Leetmark.

Problem:

Given a non-empty binary tree, find the maximum path sum.
For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.
Example 1:
1
Input: [1,2,3]
2
3
1
4
/ \
5
2 3
6
7
Output: 6
8
Copied!
Example 2:
1
Input: [-10,9,20,null,null,15,7]
2
3
-10
4
/ \
5
9 20
6
/ \
7
15 7
8
9
Output: 42
10
Copied!

Solution:

For every node, there are six possible ways to get the max path sum:
  • With node.val
    1. 1.
      node.val plus the max sum of a path that ends with node.left.
    2. 2.
      node.val plus the max sum of a path that starts with node.right.
    3. 3.
      node.val plus the max sum of both paths.
    4. 4.
      Just node.val (the max sum of both paths are negative).
  • Withoutnode.val (disconnected)
    1. 1.
      The max-sum path is somewhere under the node.left subtree.
    2. 2.
      The max-sum path is somewhere under the node.right subtree.
There are two ways to implement this.
ONE
Define a function that returns two values. The max sum of a path that may or may not end with root node, and the max sum of the path that ends with root node.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number}
11
*/
12
let maxPathSum = function(root) {
13
return Math.max(..._maxPathSum(root))
14
};
15
16
/**
17
* @param {TreeNode} root
18
* @return {number[]}
19
*/
20
function _maxPathSum (root) {
21
if (!root) { return [-Infinity, -Infinity] }
22
23
const left = _maxPathSum(root.left)
24
const right = _maxPathSum(root.right)
25
return [
26
Math.max(left[0], right[0], root.val + Math.max(0, left[1], right[1], left[1] + right[1])),
27
Math.max(left[1], right[1], 0) + root.val
28
]
29
}
Copied!
TWO
Just return the later (max sum of a path that ends with root). Maintain a global variable to store the disconnected max sum.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number}
11
*/
12
let maxPathSum = function(root) {
13
const global = { max: -Infinity }
14
_maxPathSum(root, global)
15
return global.max
16
};
17
18
19
/**
20
* @param {TreeNode} root
21
* @param {object} global
22
* @param {number} global.max
23
* @return {number[]}
24
*/
25
function _maxPathSum (root, global) {
26
if (!root) { return -Infinity }
27
28
const left = _maxPathSum(root.left, global)
29
const right = _maxPathSum(root.right, global)
30
const localMax = Math.max(left, right, 0) + root.val
31
global.max = Math.max(global.max, localMax, root.val + left + right)
32
return localMax
33
}
Copied!
Template generated via Leetmark.

Problem:

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty string as valid palindrome.
Example 1:
1
Input: "A man, a plan, a canal: Panama"
2
Output: true
3
Copied!
Example 2:
1
Input: "race a car"
2
Output: false
3
Copied!

Solution:

ONE
1
/**
2
* @param {string} s
3
* @return {boolean}
4
*/
5
let isPalindrome = function(s) {
6
const clean = s.toLowerCase().split(/[^a-z0-9]*/)
7
return clean.join('') === clean.reverse().join('')
8
};
Copied!
TWO
Remove non-alphanumeric characters then compare.
1
/**
2
* @param {string} s
3
* @return {boolean}
4
*/
5
let isPalindrome = function(s) {
6
const clean = s.replace(/[^a-zA-Z0-9]/g, '').toLowerCase()
7
for (let i = 0, j = clean.length - 1; i < j; i++, j--) {
8
if (clean[i] !== clean[j]) { return false }
9
}
10
return true
11
};
Copied!
THREE
Compare the char codes.
1
/**
2
* @param {string} s
3
* @return {boolean}
4
*/
5
let isPalindrome = function(s) {
6
for (let i = 0, j = s.length - 1; i < j; i++, j--) {
7
let left = s.charCodeAt(i)
8
while (i < j && (left < 48 || left > 57 && left < 65 || left > 90 && left < 97 || left > 122)) {
9
left = s.charCodeAt(++i)
10
}
11
if (i >= j) { return true }
12
if (left >= 65 && left <= 90) {
13
left += 32
14
}
15
16
let right = s.charCodeAt(j)
17
while (i < j && (right < 48 || right > 57 && right < 65 || right > 90 && right < 97 || right > 122)) {
18
right = s.charCodeAt(--j)
19
}
20
if (i >= j) { return true }
21
if (right >= 65 && right <= 90) {
22
right += 32
23
}
24
25
if (left !== right) { return false }
26
}
27
28
return true
29
};
Copied!
Template generated via Leetmark.

Problem:

Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:
  1. 1.
    Only one letter can be changed at a time
  2. 2.
    Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
Note:
  • Return an empty list if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume beginWord and endWord are non-empty and are not the same.
Example 1:
1
Input:
2
beginWord = "hit",
3
endWord = "cog",
4
wordList = ["hot","dot","dog","lot","log","cog"]
5
6
Output:
7
[
8
["hit","hot","dot","dog","cog"],
9
["hit","hot","lot","log","cog"]
10
]
11
Copied!
Example 2:
1
Input:
2
beginWord = "hit"
3
endWord = "cog"
4
wordList = ["hot","dot","dog","lot","log"]
5
6
Output: []
7
8
Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
9
Copied!

Solution:

This is just like 127. Word Ladder.
The constrain still works, but instead of deleting the words right away, collect them and delete them all when a level ends, so that we can reuse the words (matching different parents in the same level).
The items in the queue are not just words now. Parent nodes are also kept so that we can backtrack the path from the end.
1
/**
2
* @param {string} beginWord
3
* @param {string} endWord
4
* @param {string[]} wordList
5
* @return {string[][]}
6
*/
7
function findLadders (beginWord, endWord, wordList) {
8
wordList = new Set(wordList)
9
if (!wordList.has(endWord)) { return [] }
10
11
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
12
13
const result = []
14
let isEndWordFound = false
15
const levelWords = new Set()
16
const queue = [[beginWord, null], null]
17
while (queue.length > 1) {
18
const node = queue.shift()
19
20
if (node === null) {
21
if (isEndWordFound) {
22
break
23
}
24
levelWords.forEach(word => wordList.delete(word))
25
levelWords.clear()
26
queue.push(null)
27
continue
28
}
29
30
const word = node[0]
31
32
for (let i = word.length - 1; i >= 0; i--) {
33
const head = word.slice(0, i)
34
const tail = word.slice(i+1)
35
36
for (let c = 0; c < 26; c++) {
37
if (ALPHABET[c] !== word[i]) {
38
const w = head + ALPHABET[c] + tail
39
if (w === endWord) {
40
const path = [endWord]
41
for (let n = node; n !== null; n = n[1]) {
42
path.unshift(n[0])
43
}
44
result.push(path)
45
isEndWordFound = true
46
}
47
if (wordList.has(w)) {
48
levelWords.add(w)
49
queue.push([w, node])
50
}
51
}
52
}
53
}
54
}
55
56
return result
57
};
Copied!
Template generated via Leetmark.

Problem:

Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
  1. 1.
    Only one letter can be changed at a time.
  2. 2.
    Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
Note:
  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume beginWord and endWord are non-empty and are not the same.
Example 1:
1
Input:
2
beginWord = "hit",
3
endWord = "cog",
4
wordList = ["hot","dot","dog","lot","log","cog"]
5
6
Output: 5
7
8
Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
9
return its length 5.
10
Copied!
Example 2:
1
Input:
2
beginWord = "hit"
3
endWord = "cog"
4
wordList = ["hot","dot","dog","lot","log"]
5
6
Output: 0
7
8
Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
9
Copied!

Solution:

Think of it as building a tree, with begineWord as root and endWord as leaves.
The best way control the depth (length of the shortest transformations) while building the tree is level-order traversal (BFS).
We do not actually build the tree because it is expensive (astronomical if the list is huge). In fact, we only need one shortest path. So just like Dijkstra's algorithm, we say that the first time (level i) we encounter a word that turns out to be in a shortest path, then level i is the lowest level this word could ever get. We can safely remove it from the wordList.
To find all the next words, instead of filtering the wordList, enumerate all 25 possible words and check if in wordList.
1
/**
2
* @param {string} beginWord
3
* @param {string} endWord
4
* @param {string[]} wordList
5
* @return {number}
6
*/
7
let ladderLength = function(beginWord, endWord, wordList) {
8
wordList = new Set(wordList)
9
if (!wordList.has(endWord)) { return 0 }
10
11
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
12
13
let level = 1
14
const queue = [beginWord, null]
15
while (queue.length > 1) {
16
const word = queue.shift()
17
18
if (word === null) {
19
level++
20
queue.push(null)
21
continue
22
}
23
24
for (let i = word.length - 1; i >= 0; i--) {
25
const head = word.slice(0, i)
26
const tail = word.slice(i+1)
27
28
for (let c = 0; c < 26; c++) {
29
if (ALPHABET[c] !== word[i]) {
30
const word = head + ALPHABET[c] + tail
31
if (word === endWord) {
32
return level + 1
33
}
34
if (wordList.delete(word)) {
35
queue.push(word)
36
}
37
}
38
}
39
}
40
}
41
42
return 0
43
};
Copied!
Template generated via Leetmark.

Problem:

Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
Your algorithm should run in O(n) complexity.
Example:
1
Input: [100, 4, 200, 1, 3, 2]
2
Output: 4
3
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
4
Copied!

Solution:

Build a Set from the list. Pick a number, find all it's adjacent numbers that are also in the Set. Count them and remove them all from the Set. Repeat until the Set is empty. Time complexity O(n + n) = O(n).
1
/**
2
* @param {number[]} nums
3
* @return {number}
4
*/
5
let longestConsecutive = function(nums) {
6
const numSet = new Set(nums)
7
let maxCount = 0
8
while (numSet.size > 0) {
9
const num = numSet.values().next().value
10
numSet.delete(num)
11
let count = 1
12
for (let n = num + 1; numSet.delete(n); n++) {
13
count++
14
}
15
for (let n = num - 1; numSet.delete(n); n--) {
16
count++
17
}
18
if (count > maxCount) {
19
maxCount = count
20
}
21
}
22
return maxCount
23
};
Copied!
Template generated via Leetmark.

Problem:

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path 1->2->3 which represents the number 123.
Find the total sum of all root-to-leaf numbers.
Note: A leaf is a node with no children.
Example:
1
Input: [1,2,3]
2
1
3
/ \
4
2 3
5
Output: 25
6
Explanation:
7
The root-to-leaf path 1->2 represents the number 12.
8
The root-to-leaf path 1->3 represents the number 13.
9
Therefore, sum = 12 + 13 = 25.
Copied!
Example 2:
1
Input: [4,9,0,5,1]
2
4
3
/ \
4
9 0
5
/ \
6
5 1
7
Output: 1026
8
Explanation:
9
The root-to-leaf path 4->9->5 represents the number 495.
10
The root-to-leaf path 4->9->1 represents the number 491.
11
The root-to-leaf path 4->0 represents the number 40.
12
Therefore, sum = 495 + 491 + 40 = 1026.
Copied!

Solution:

To write a clean solution for this promblem, use 0 as indicator of leaf node. If all the children get 0, it is a leaf node, return the sum of current level.
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {number}
11
*/
12
let sumNumbers = function(root, sum = 0) {
13
if (!root) { return 0 }
14
sum = sum * 10 + root.val
15
return sumNumbers(root.left, sum) + sumNumbers(root.right, sum) || sum
16
};
Copied!
Template generated via Leetmark.

Problem:

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
Example:
1
X X X X
2
X O O X
3
X X O X
4
X O X X
5
Copied!
After running your function, the board should be:
1
X X X X
2
X X X X
3
X X X X
4
X O X X
5
Copied!
Explanation:
Surrounded regions shouldn't be on the border, which means that any 'O' on the border of the board are not flipped to 'X'. Any 'O' that is not on the border and it is not connected to an 'O' on the border will be flipped to 'X'. Two cells are connected if they are adjacent cells connected horizontally or vertically.

Solution:

Find all the Os that are connected to the Os on the border, change them to #. Then scan the board, change O to X and # back to O.
The process of finding the connected Os is just like tree traversal. Os on the border are the same level. Their children are the second level. And so on.
So both BFS and DFS are good. I prefer BFS when pruning is not needed in favor of its readability.
1
/**
2
* @param {character[][]} board
3
* @return {void} Do not return anything, modify board in-place instead.
4
*/
5
let solve = function(board) {
6
const height = board.length
7
if (height <= 1) { return }
8
const width = board[0].length
9
if (width <= 1) { return }
10
11
const rowend = height - 1
12
const colend = width - 1
13
14
const queue = []
15
16
for (let row = 0; row < height; row++) {
17
if (board[row][0] === 'O') {
18
board[row][0] = '#'
19
queue.push(row, 0)
20
}
21
if (board[row][colend] === 'O') {
22
board[row][colend] = '#'
23
queue.push(row, colend)
24
}
25
}
26
27
for (let col = 0; col < width; col++) {
28
if (board[0][col] === 'O') {
29
board[0][col] = '#'
30
queue.push(0, col)
31
}
32
if (board[rowend][col] === 'O') {
33
board[rowend][col] = '#'
34
queue.push(rowend, col)
35
}
36
}
37
38
while (queue.length > 0) {
39
const row = queue.shift()
40
const col = queue.shift()
41
if (row < rowend && board[row + 1][col] === 'O') {
42
board[row + 1][col] = '#'
43
queue.push(row + 1, col)
44
}
45
if (row > 0 && board[row - 1][col] === 'O') {
46
board[row - 1][col] = '#'
47
queue.push(row - 1, col)
48
}
49
if (board[row][col + 1] === 'O') {
50
board[row][col + 1] = '#'
51
queue.push(row, col + 1)
52
}
53
if (board[row][col - 1] === 'O') {
54
board[row][col - 1] = '#'
55
queue.push(row, col - 1)
56
}
57
}
58
59
for (let row = 0; row < height; row++) {
60
for (let col = 0; col < width; col++) {
61
if (board[row][col] === '#') {
62
board[row][col] = 'O'
63
} else if (board[row][col] === 'O') {
64
board[row][col] = 'X'
65
}
66
}
67
}
68
};
Copied!
Template generated via Leetmark.

Problem:

Given the head of a graph, return a deep copy (clone) of the graph. Each node in the graph contains a label (int) and a list (List[UndirectedGraphNode]) of its neighbors. There is an edge between the given node and each of the nodes in its neighbors.
OJ's undirected graph serialization (so you can understand error output):
Nodes are labeled uniquely.
We use # as a separator for each node, and , as a separator for node label and each neighbor of the node.
As an example, consider the serialized graph {0,1,2#1,2#2,2}.
The graph has a total of three nodes, and therefore contains three parts as separated by #.
  1. 1.
    First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
  2. 2.
    Second node is labeled as 1. Connect node 1 to node 2.
  3. 3.
    Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle.
Visually, the graph looks like the following:
1
1
2
/ \
3
/ \
4
0 --- 2
5
/ \
6
\_/
7
Copied!
Note: The information about the tree serialization is only meant so that you can understand error output if you get a wrong answer. You don't need to understand the serialization to solve the problem.

Solution:

DFS. Cache the visited node before entering the next recursion.
1
/**
2
* Definition for undirected graph.
3
* function UndirectedGraphNode(label) {
4
* this.label = label;
5
* this.neighbors = []; // Array of UndirectedGraphNode
6
* }
7
*/
8
9
/**
10
* @param {UndirectedGraphNode} graph
11
* @return {UndirectedGraphNode}
12
*/
13
let cloneGraph = function(graph) {
14
const cache = {}
15
return _clone(graph)
16
17
function _clone (graph) {
18
if (!graph) { return graph }
19
const label = graph.label
20
if (!cache[label]) {
21
cache[label] = new UndirectedGraphNode(label)
22
cache[label].neighbors = graph.neighbors.map(_clone)
23
}
24
return cache[label]
25
}
26
};
Copied!
Template generated via Leetmark.
Could not load image
alt text
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
/**
9
* @param {TreeNode} root
10
* @return {TreeNode}
11
*/
12
const upsideDownBinaryTree = function(root) {
13
let curr = root
14
let next = null
15
let temp = null
16
let prev = null
17
while (curr !== null) {
18
next = curr.left
19
curr.left = temp
20
temp = curr.right
21
curr.right = prev
22
prev = curr
23
curr = next
24
}
25
return prev
26
}
27
28
// another
29
30
const upsideDownBinaryTree = function(root) {
31
if (root == null || root.left == null) {
32
return root
33
}
34
const newRoot = upsideDownBinaryTree(root.left)
35
root.left.left = root.right
36
root.left.right = root
37
root.left = null
38
root.right = null
39
return newRoot
40
}
Copied!
Could not load image
alt text
1
/**
2
* @param {number[]} A
3
* @return {number}
4
*/
5
const maxSubarraySumCircular = function(A) {
6
let minSum = Infinity, sum = 0, maxSum = -Infinity, curMax = 0, curMin = 0
7
for(let a of A) {
8
sum += a
9
curMax = Math.max(curMax + a, a);
10
maxSum = Math.max(maxSum, curMax);
11
curMin = Math.min(curMin + a, a);
12
minSum = Math.min(minSum, curMin);
13
}
14
return maxSum > 0 ? Math.max(maxSum, sum - minSum) : maxSum;
15
};
Copied!

Balanced Binary Tree - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.
Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as:
a binary tree in which the left and right subtrees of every node differ in height by no more than 1.
Example 1:
Could not load image
Input: root =3,9,20,null,null,15,73,9,20,null,null,15,7 Output: true
Example 2:
Could not load image
Input: root =1,2,2,3,3,null,null,4,41,2,2,3,3,null,null,4,4 Output: false
Example 3:
Input: root = [] Output: true
Constraints:
  • The number of nodes in the tree is in the range [0, 5000].
  • -104 <= Node.val <= 104
Source# Convert Sorted Array to Binary Search Tree
Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.
Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
Example:
Given the sorted array:-10,-3,0,5,9−10,−3,0,5,9,
One possible answer is:0,-3,9,-10,null,50,−3,9,−10,null,5, which represents the following height balanced BST:
1
0
2
/ \\
Copied!
-3 9 / / -10 5
Source# Delete Node in a BST
Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.
Basically, the deletion can be divided into two stages:
  1. 1.
    Search for a node to remove.
  2. 2.
    If the node is found, delete the node.
Follow up: Can you solve it with time complexity O(height of tree)?
Example 1:
Could not load image
Input: root =5,3,6,2,4,null,75,3,6,2,4,null,7, key = 3 Output:5,4,6,2,null,null,75,4,6,2,null,null,7 Explanation: Given key to delete is 3. So we find the node with value 3 and delete it. One valid answer is5,4,6,2,null,null,75,4,6,2,null,null,7, shown in the above BST. Please notice that another valid answer is5,2,6,null,4,null,75,2,6,null,4,null,7and it's also accepted.
Example 2:
Input: root =5,3,6,2,4,null,75,3,6,2,4,null,7, key = 0 Output:5,3,6,2,4,null,75,3,6,2,4,null,7 Explanation: The tree does not contain a node with value = 0.
Example 3:
Input: root = [], key = 0 Output: []
Constraints:
  • The number of nodes in the tree is in the range [0, 104].
  • -105 <= Node.val <= 105
  • Each node has a unique value.
  • root is a valid binary search tree.
  • -105 <= key <= 105
Source
1
/**
2
* @param {number[][]} intervals
3
* @return {number}
4
*/
5
const minMeetingRooms = function(intervals) {
6
const len = intervals.length
7
const starts = new Array(len)
8
const ends = new Array(len)
9
for (let i = 0; i < len; i++) {
10
starts[i] = intervals[i][0]
11
ends[i] = intervals[i][1]
12
}
13
starts.sort((a, b) => a - b)
14
ends.sort((a, b) => a - b)
15
let rooms = 0
16
let endsIdx = 0
17
for (let i = 0; i < len; i++) {
18
if (starts[i] < ends[endsIdx]) rooms++
19
else endsIdx++
20
}
21
return rooms
22
}
Copied!
Last modified 3mo ago
Export as PDF
Copy link
Contents
2. Add Two Numbers
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Binary Search": https://leetcode.com/tag/binary-search "Divide and Conquer": https://leetcode.com/tag/divide-and-conquer
4. Median of Two Sorted Arrays
Difficulty: Medium Related Topics: "String": https://leetcode.com/tag/string
6. ZigZag Conversion
Difficulty: Easy Related Topics: "Math": https://leetcode.com/tag/math Similar Questions: "String to Integer (atoi)": https://leetcode.com/problems/string-to-integer-atoi
7. Reverse Integer
Difficulty: Medium Related Topics: "Math": https://leetcode.com/tag/math "String": https://leetcode.com/tag/string Similar Questions: "Reverse Integer": https://leetcode.com/problems/reverse-integer "Valid Number": https://leetcode.com/problems/valid-number
8. String to Integer (atoi)
Difficulty: Easy Related Topics: "Math": https://leetcode.com/tag/math Similar Questions: "Palindrome Linked List": https://leetcode.com/problems/palindrome-linked-list
9. Palindrome Number
Difficulty: Hard Related Topics: "String": https://leetcode.com/tag/string "Dynamic Programming": https://leetcode.com/tag/dynamic-programming "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Wildcard Matching": https://leetcode.com/problems/wildcard-matching
10. Regular Expression Matching
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Trapping Rain Water": https://leetcode.com/problems/trapping-rain-water
11. Container With Most Water
Difficulty: Medium Related Topics: "Math": https://leetcode.com/tag/math "String": https://leetcode.com/tag/string Similar Questions: "Roman to Integer": https://leetcode.com/problems/roman-to-integer "Integer to English Words": https://leetcode.com/problems/integer-to-english-words
12. Integer to Roman
Difficulty: Easy Related Topics: "Math": https://leetcode.com/tag/math "String": https://leetcode.com/tag/string Similar Questions: "Integer to Roman": https://leetcode.com/problems/integer-to-roman
13. Roman to Integer
Difficulty: Easy Related Topics: "String": https://leetcode.com/tag/string
14. Longest Common Prefix
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Two Sum": https://leetcode.com/problems/two-sum "3Sum Closest": https://leetcode.com/problems/3sum-closest "4Sum": https://leetcode.com/problems/4sum "3Sum Smaller": https://leetcode.com/problems/3sum-smaller
15. 3Sum
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "3Sum": https://leetcode.com/problems/3sum "3Sum Smaller": https://leetcode.com/problems/3sum-smaller
16. 3Sum Closest
Difficulty: Medium Related Topics: "String": https://leetcode.com/tag/string "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Generate Parentheses": https://leetcode.com/problems/generate-parentheses "Combination Sum": https://leetcode.com/problems/combination-sum "Binary Watch": https://leetcode.com/problems/binary-watch
17. Letter Combinations of a Phone Number
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Hash Table": https://leetcode.com/tag/hash-table "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Two Sum": https://leetcode.com/problems/two-sum "3Sum": https://leetcode.com/problems/3sum "4Sum II": https://leetcode.com/problems/4sum-ii
18. 4Sum
Difficulty: Medium Related Topics: "Linked List": https://leetcode.com/tag/linked-list "Two Pointers": https://leetcode.com/tag/two-pointers
19. Remove Nth Node From End of List
Difficulty: Easy Related Topics: "String": https://leetcode.com/tag/string "Stack": https://leetcode.com/tag/stack Similar Questions: "Generate Parentheses": https://leetcode.com/problems/generate-parentheses "Longest Valid Parentheses": https://leetcode.com/problems/longest-valid-parentheses "Remove Invalid Parentheses": https://leetcode.com/problems/remove-invalid-parentheses
20. Valid Parentheses
Difficulty: Easy Related Topics: "Linked List": https://leetcode.com/tag/linked-list Similar Questions: "Merge k Sorted Lists": https://leetcode.com/problems/merge-k-sorted-lists "Merge Sorted Array": https://leetcode.com/problems/merge-sorted-array "Sort List": https://leetcode.com/problems/sort-list "Shortest Word Distance II": https://leetcode.com/problems/shortest-word-distance-ii
21. Merge Two Sorted Lists
Difficulty: Medium Related Topics: "String": https://leetcode.com/tag/string "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Letter Combinations of a Phone Number": https://leetcode.com/problems/letter-combinations-of-a-phone-number "Valid Parentheses": https://leetcode.com/problems/valid-parentheses
22. Generate Parentheses
Difficulty: Hard Related Topics: "Linked List": https://leetcode.com/tag/linked-list "Divide and Conquer": https://leetcode.com/tag/divide-and-conquer "Heap": https://leetcode.com/tag/heap Similar Questions: "Merge Two Sorted Lists": https://leetcode.com/problems/merge-two-sorted-lists "Ugly Number II": https://leetcode.com/problems/ugly-number-ii
23. Merge k Sorted Lists
Difficulty: Medium Related Topics: "Linked List": https://leetcode.com/tag/linked-list Similar Questions: "Reverse Nodes in k-Group": https://leetcode.com/problems/reverse-nodes-in-k-group
24. Swap Nodes in Pairs
Difficulty: Hard Related Topics: "Linked List": https://leetcode.com/tag/linked-list Similar Questions: "Swap Nodes in Pairs": https://leetcode.com/problems/swap-nodes-in-pairs
25. Reverse Nodes in k-Group
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Remove Element": https://leetcode.com/problems/remove-element "Remove Duplicates from Sorted Array II": https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii
26. Remove Duplicates from Sorted Array
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Remove Duplicates from Sorted Array": https://leetcode.com/problems/remove-duplicates-from-sorted-array "Remove Linked List Elements": https://leetcode.com/problems/remove-linked-list-elements "Move Zeroes": https://leetcode.com/problems/move-zeroes
27. Remove Element
Difficulty: Medium Related Topics: "Math": https://leetcode.com/tag/math "Binary Search": https://leetcode.com/tag/binary-search
29. Divide Two Integers
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array Similar Questions: "Permutations": https://leetcode.com/problems/permutations "Permutations II": https://leetcode.com/problems/permutations-ii "Permutation Sequence": https://leetcode.com/problems/permutation-sequence "Palindrome Permutation II": https://leetcode.com/problems/palindrome-permutation-ii
31. Next Permutation
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Binary Search": https://leetcode.com/tag/binary-search Similar Questions: "Search in Rotated Sorted Array II": https://leetcode.com/problems/search-in-rotated-sorted-array-ii "Find Minimum in Rotated Sorted Array": https://leetcode.com/problems/find-minimum-in-rotated-sorted-array
33. Search in Rotated Sorted Array
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Binary Search": https://leetcode.com/tag/binary-search Similar Questions: "First Bad Version": https://leetcode.com/problems/first-bad-version
34. Find First and Last Position of Element in Sorted Array
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Binary Search": https://leetcode.com/tag/binary-search Similar Questions: "First Bad Version": https://leetcode.com/problems/first-bad-version
35. Search Insert Position
Difficulty: Medium Related Topics: "Hash Table": https://leetcode.com/tag/hash-table Similar Questions: "Sudoku Solver": https://leetcode.com/problems/sudoku-solver
36. Valid Sudoku
Difficulty: Hard Related Topics: "Hash Table": https://leetcode.com/tag/hash-table "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Valid Sudoku": https://leetcode.com/problems/valid-sudoku
37. Sudoku Solver
Difficulty: Easy Related Topics: "String": https://leetcode.com/tag/string Similar Questions: "Encode and Decode Strings": https://leetcode.com/problems/encode-and-decode-strings "String Compression": https://leetcode.com/problems/string-compression
38. Count and Say
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Letter Combinations of a Phone Number": https://leetcode.com/problems/letter-combinations-of-a-phone-number "Combination Sum II": https://leetcode.com/problems/combination-sum-ii "Combinations": https://leetcode.com/problems/combinations "Combination Sum III": https://leetcode.com/problems/combination-sum-iii "Factor Combinations": https://leetcode.com/problems/factor-combinations "Combination Sum IV": https://leetcode.com/problems/combination-sum-iv
39. Combination Sum
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Combination Sum": https://leetcode.com/problems/combination-sum
40. Combination Sum II
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array Similar Questions: "Missing Number": https://leetcode.com/problems/missing-number "Find the Duplicate Number": https://leetcode.com/problems/find-the-duplicate-number "Find All Numbers Disappeared in an Array": https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array "Couples Holding Hands": https://leetcode.com/problems/couples-holding-hands
41. First Missing Positive
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers "Stack": https://leetcode.com/tag/stack Similar Questions: "Container With Most Water": https://leetcode.com/problems/CONTENT-with-most-water "Product of Array Except Self": https://leetcode.com/problems/product-of-array-except-self "Trapping Rain Water II": https://leetcode.com/problems/trapping-rain-water-ii "Pour Water": https://leetcode.com/problems/pour-water
42. Trapping Rain Water
Difficulty: Medium Related Topics: "Math": https://leetcode.com/tag/math "String": https://leetcode.com/tag/string Similar Questions: "Add Two Numbers": https://leetcode.com/problems/add-two-numbers "Plus One": https://leetcode.com/problems/plus-one "Add Binary": https://leetcode.com/problems/add-binary "Add Strings": https://leetcode.com/problems/add-strings
43. Multiply Strings
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Greedy": https://leetcode.com/tag/greedy Similar Questions: "Jump Game": https://leetcode.com/problems/jump-game
45. Jump Game II
Difficulty: Medium Related Topics: "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Next Permutation": https://leetcode.com/problems/next-permutation "Permutations II": https://leetcode.com/problems/permutations-ii "Permutation Sequence": https://leetcode.com/problems/permutation-sequence "Combinations": https://leetcode.com/problems/combinations
46. Permutations
Difficulty: Medium Related Topics: "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Next Permutation": https://leetcode.com/problems/next-permutation "Permutations": https://leetcode.com/problems/permutations "Palindrome Permutation II": https://leetcode.com/problems/palindrome-permutation-ii
47. Permutations II
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array
48. Rotate Image
Difficulty: Medium Related Topics: "Hash Table": https://leetcode.com/tag/hash-table "String": https://leetcode.com/tag/string Similar Questions: "Valid Anagram": https://leetcode.com/problems/valid-anagram "Group Shifted Strings": https://leetcode.com/problems/group-shifted-strings
49. Group Anagrams
Difficulty: Medium Related Topics: "Math": https://leetcode.com/tag/math "Binary Search": https://leetcode.com/tag/binary-search Similar Questions: "Sqrt(x)": https://leetcode.com/problems/sqrtx "Super Pow": https://leetcode.com/problems/super-pow
50. Pow(x, n)
Difficulty: Hard Related Topics: "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "N-Queens II": https://leetcode.com/problems/n-queens-ii
51. N-Queens
Difficulty: Hard Related Topics: "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "N-Queens": https://leetcode.com/problems/n-queens
52. N-Queens II
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Divide and Conquer": https://leetcode.com/tag/divide-and-conquer "Dynamic Programming": https://leetcode.com/tag/dynamic-programming Similar Questions: "Best Time to Buy and Sell Stock": https://leetcode.com/problems/best-time-to-buy-and-sell-stock "Maximum Product Subarray": https://leetcode.com/problems/maximum-product-subarray "Degree of an Array": https://leetcode.com/problems/degree-of-an-array
53. Maximum Subarray
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array Similar Questions: "Spiral Matrix II": https://leetcode.com/problems/spiral-matrix-ii
54. Spiral Matrix
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Greedy": https://leetcode.com/tag/greedy Similar Questions: "Jump Game II": https://leetcode.com/problems/jump-game-ii
55. Jump Game
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Sort": https://leetcode.com/tag/sort Similar Questions: "Insert Interval": https://leetcode.com/problems/insert-interval "Meeting Rooms": https://leetcode.com/problems/meeting-rooms "Meeting Rooms II": https://leetcode.com/problems/meeting-rooms-ii "Teemo Attacking": https://leetcode.com/problems/teemo-attacking "Add Bold Tag in String": https://leetcode.com/problems/add-bold-tag-in-string "Range Module": https://leetcode.com/problems/range-module "Employee Free Time": https://leetcode.com/problems/employee-free-time "Partition Labels": https://leetcode.com/problems/partition-labels
56. Merge Intervals
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Sort": https://leetcode.com/tag/sort Similar Questions: "Merge Intervals": https://leetcode.com/problems/merge-intervals "Range Module": https://leetcode.com/problems/range-module
57. Insert Interval
Difficulty: Easy Related Topics: "String": https://leetcode.com/tag/string
58. Length of Last Word
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array Similar Questions: "Spiral Matrix": https://leetcode.com/problems/spiral-matrix
59. Spiral Matrix II
Difficulty: Medium Related Topics: "Math": https://leetcode.com/tag/math "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Next Permutation": https://leetcode.com/problems/next-permutation "Permutations": https://leetcode.com/problems/permutations
60. Permutation Sequence
Difficulty: Medium Related Topics: "Linked List": https://leetcode.com/tag/linked-list "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Rotate Array": https://leetcode.com/problems/rotate-array "Split Linked List in Parts": https://leetcode.com/problems/split-linked-list-in-parts
61. Rotate List
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Dynamic Programming": https://leetcode.com/tag/dynamic-programming Similar Questions: "Unique Paths II": https://leetcode.com/problems/unique-paths-ii "Minimum Path Sum": https://leetcode.com/problems/minimum-path-sum "Dungeon Game": https://leetcode.com/problems/dungeon-game
62. Unique Paths
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Dynamic Programming": https://leetcode.com/tag/dynamic-programming Similar Questions: "Unique Paths": https://leetcode.com/problems/unique-paths "Dungeon Game": https://leetcode.com/problems/dungeon-game "Cherry Pickup": https://leetcode.com/problems/cherry-pickup
64. Minimum Path Sum
Difficulty: Hard Related Topics: "Math": https://leetcode.com/tag/math "String": https://leetcode.com/tag/string Similar Questions: "String to Integer (atoi)": https://leetcode.com/problems/string-to-integer-atoi
65. Valid Number
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Math": https://leetcode.com/tag/math Similar Questions: "Multiply Strings": https://leetcode.com/problems/multiply-strings "Add Binary": https://leetcode.com/problems/add-binary "Plus One Linked List": https://leetcode.com/problems/plus-one-linked-list
66. Plus One
Difficulty: Hard Related Topics: "String": https://leetcode.com/tag/string
68. Text Justification
Difficulty: Easy Related Topics: "Math": https://leetcode.com/tag/math "Binary Search": https://leetcode.com/tag/binary-search Similar Questions: "Pow(x, n)": https://leetcode.com/problems/powx-n "Valid Perfect Square": https://leetcode.com/problems/valid-perfect-square
69. Sqrt(x)
Difficulty: Medium Related Topics: "String": https://leetcode.com/tag/string "Stack": https://leetcode.com/tag/stack
71. Simplify Path
Difficulty: Hard Related Topics: "String": https://leetcode.com/tag/string "Dynamic Programming": https://leetcode.com/tag/dynamic-programming Similar Questions: "One Edit Distance": https://leetcode.com/problems/one-edit-distance "Delete Operation for Two Strings": https://leetcode.com/problems/delete-operation-for-two-strings "Minimum ASCII Delete Sum for Two Strings": https://leetcode.com/problems/minimum-ascii-delete-sum-for-two-strings
72. Edit Distance
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array Similar Questions: "Game of Life": https://leetcode.com/problems/game-of-life
73. Set Matrix Zeroes
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Binary Search": https://leetcode.com/tag/binary-search Similar Questions: "Search a 2D Matrix II": https://leetcode.com/problems/search-a-2d-matrix-ii
74. Search a 2D Matrix
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers "Sort": https://leetcode.com/tag/sort Similar Questions: "Sort List": https://leetcode.com/problems/sort-list "Wiggle Sort": https://leetcode.com/problems/wiggle-sort "Wiggle Sort II": https://leetcode.com/problems/wiggle-sort-ii
75. Sort Colors
Difficulty: Medium Related Topics: "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Combination Sum": https://leetcode.com/problems/combination-sum "Permutations": https://leetcode.com/problems/permutations
77. Combinations
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Backtracking": https://leetcode.com/tag/backtracking "Bit Manipulation": https://leetcode.com/tag/bit-manipulation Similar Questions: "Subsets II": https://leetcode.com/problems/subsets-ii "Generalized Abbreviation": https://leetcode.com/problems/generalized-abbreviation "Letter Case Permutation": https://leetcode.com/problems/letter-case-permutation
78. Subsets
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Word Search II": https://leetcode.com/problems/word-search-ii
79. Word Search
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Remove Duplicates from Sorted Array": https://leetcode.com/problems/remove-duplicates-from-sorted-array
80. Remove Duplicates from Sorted Array II
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Binary Search": https://leetcode.com/tag/binary-search Similar Questions: "Search in Rotated Sorted Array": https://leetcode.com/problems/search-in-rotated-sorted-array
81. Search in Rotated Sorted Array II
Difficulty: Medium Related Topics: "Linked List": https://leetcode.com/tag/linked-list Similar Questions: "Remove Duplicates from Sorted List": https://leetcode.com/problems/remove-duplicates-from-sorted-list
82. Remove Duplicates from Sorted List II
Difficulty: Easy Related Topics: "Linked List": https://leetcode.com/tag/linked-list Similar Questions: "Remove Duplicates from Sorted List II": https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii
83. Remove Duplicates from Sorted List
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Stack": https://leetcode.com/tag/stack Similar Questions: "Maximal Rectangle": https://leetcode.com/problems/maximal-rectangle
84. Largest Rectangle in Histogram
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Hash Table": https://leetcode.com/tag/hash-table "Dynamic Programming": https://leetcode.com/tag/dynamic-programming "Stack": https://leetcode.com/tag/stack Similar Questions: "Largest Rectangle in Histogram": https://leetcode.com/problems/largest-rectangle-in-histogram "Maximal Square": https://leetcode.com/problems/maximal-square
85. Maximal Rectangle
Difficulty: Medium Related Topics: "Linked List": https://leetcode.com/tag/linked-list "Two Pointers": https://leetcode.com/tag/two-pointers
86. Partition List
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Two Pointers": https://leetcode.com/tag/two-pointers Similar Questions: "Merge Two Sorted Lists": https://leetcode.com/problems/merge-two-sorted-lists
88. Merge Sorted Array
Difficulty: Medium Related Topics: "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "1-bit and 2-bit Characters": https://leetcode.com/problems/1-bit-and-2-bit-characters
89. Gray Code
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "Subsets": https://leetcode.com/problems/subsets
90. Subsets II
Difficulty: Medium Related Topics: "String": https://leetcode.com/tag/string "Dynamic Programming": https://leetcode.com/tag/dynamic-programming Similar Questions: "Decode Ways II": https://leetcode.com/problems/decode-ways-ii
91. Decode Ways
Difficulty: Medium Related Topics: "Linked List": https://leetcode.com/tag/linked-list Similar Questions: "Reverse Linked List": https://leetcode.com/problems/reverse-linked-list
92. Reverse Linked List II
Difficulty: Medium Related Topics: "String": https://leetcode.com/tag/string "Backtracking": https://leetcode.com/tag/backtracking Similar Questions: "IP to CIDR": https://leetcode.com/problems/ip-to-cidr
93. Restore IP Addresses
Difficulty: Hard Related Topics: "String": https://leetcode.com/tag/string "Dynamic Programming": https://leetcode.com/tag/dynamic-programming
97. Interleaving String
Difficulty: Easy Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search
100. Same Tree
Difficulty: Easy Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search "Breadth-first Search": https://leetcode.com/tag/breadth-first-search
101. Symmetric Tree
Difficulty: Medium Related Topics: "Tree": https://leetcode.com/tag/tree "Breadth-first Search": https://leetcode.com/tag/breadth-first-search Similar Questions: "Binary Tree Zigzag Level Order Traversal": https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal "Binary Tree Level Order Traversal II": https://leetcode.com/problems/binary-tree-level-order-traversal-ii "Minimum Depth of Binary Tree": https://leetcode.com/problems/minimum-depth-of-binary-tree "Binary Tree Vertical Order Traversal": https://leetcode.com/problems/binary-tree-vertical-order-traversal "Average of Levels in Binary Tree": https://leetcode.com/problems/average-of-levels-in-binary-tree "N-ary Tree Level Order Traversal": https://leetcode.com/problems/n-ary-tree-level-order-traversal
102. Binary Tree Level Order Traversal
Difficulty: Medium Related Topics: "Stack": https://leetcode.com/tag/stack "Tree": https://leetcode.com/tag/tree "Breadth-first Search": https://leetcode.com/tag/breadth-first-search Similar Questions: "Binary Tree Level Order Traversal": https://leetcode.com/problems/binary-tree-level-order-traversal
103. Binary Tree Zigzag Level Order Traversal
Difficulty: Easy Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Balanced Binary Tree": https://leetcode.com/problems/balanced-binary-tree "Minimum Depth of Binary Tree": https://leetcode.com/problems/minimum-depth-of-binary-tree "Maximum Depth of N-ary Tree": https://leetcode.com/problems/maximum-depth-of-n-ary-tree
104. Maximum Depth of Binary Tree
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Construct Binary Tree from Inorder and Postorder Traversal": https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal
105. Construct Binary Tree from Preorder and Inorder Traversal
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Construct Binary Tree from Preorder and Inorder Traversal": https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
106. Construct Binary Tree from Inorder and Postorder Traversal
Difficulty: Easy Related Topics: "Tree": https://leetcode.com/tag/tree "Breadth-first Search": https://leetcode.com/tag/breadth-first-search Similar Questions: "Binary Tree Level Order Traversal": https://leetcode.com/problems/binary-tree-level-order-traversal "Average of Levels in Binary Tree": https://leetcode.com/problems/average-of-levels-in-binary-tree
107. Binary Tree Level Order Traversal II
Difficulty: Easy Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Maximum Depth of Binary Tree": https://leetcode.com/problems/maximum-depth-of-binary-tree
110. Balanced Binary Tree
Difficulty: Easy Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search "Breadth-first Search": https://leetcode.com/tag/breadth-first-search Similar Questions: "Binary Tree Level Order Traversal": https://leetcode.com/problems/binary-tree-level-order-traversal "Maximum Depth of Binary Tree": https://leetcode.com/problems/maximum-depth-of-binary-tree
111. Minimum Depth of Binary Tree
Difficulty: Easy Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Path Sum II": https://leetcode.com/problems/path-sum-ii "Binary Tree Maximum Path Sum": https://leetcode.com/problems/binary-tree-maximum-path-sum "Sum Root to Leaf Numbers": https://leetcode.com/problems/sum-root-to-leaf-numbers "Path Sum III": https://leetcode.com/problems/path-sum-iii "Path Sum IV": https://leetcode.com/problems/path-sum-iv
112. Path Sum
Difficulty: Medium Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Path Sum": https://leetcode.com/problems/path-sum "Binary Tree Paths": https://leetcode.com/problems/binary-tree-paths "Path Sum III": https://leetcode.com/problems/path-sum-iii "Path Sum IV": https://leetcode.com/problems/path-sum-iv
113. Path Sum II
Difficulty: Medium Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Flatten a Multilevel Doubly Linked List": https://leetcode.com/problems/flatten-a-multilevel-doubly-linked-list
114. Flatten Binary Tree to Linked List
Difficulty: Hard Related Topics: "String": https://leetcode.com/tag/string "Dynamic Programming": https://leetcode.com/tag/dynamic-programming
115. Distinct Subsequences
Difficulty: Medium Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Populating Next Right Pointers in Each Node II": https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii "Binary Tree Right Side View": https://leetcode.com/problems/binary-tree-right-side-view
116. Populating Next Right Pointers in Each Node
Difficulty: Medium Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Populating Next Right Pointers in Each Node": https://leetcode.com/problems/populating-next-right-pointers-in-each-node
117. Populating Next Right Pointers in Each Node II
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array Similar Questions: "Pascal's Triangle II": https://leetcode.com/problems/pascals-triangle-ii
118. Pascal's Triangle
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array Similar Questions: "Pascal's Triangle": https://leetcode.com/problems/pascals-triangle
119. Pascal's Triangle II
Difficulty: Medium Related Topics: "Array": https://leetcode.com/tag/array "Dynamic Programming": https://leetcode.com/tag/dynamic-programming
120. Triangle
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Dynamic Programming": https://leetcode.com/tag/dynamic-programming Similar Questions: "Maximum Subarray": https://leetcode.com/problems/maximum-subarray "Best Time to Buy and Sell Stock II": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii "Best Time to Buy and Sell Stock III": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii "Best Time to Buy and Sell Stock IV": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv "Best Time to Buy and Sell Stock with Cooldown": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown
121. Best Time to Buy and Sell Stock
Difficulty: Easy Related Topics: "Array": https://leetcode.com/tag/array "Greedy": https://leetcode.com/tag/greedy Similar Questions: "Best Time to Buy and Sell Stock": https://leetcode.com/problems/best-time-to-buy-and-sell-stock "Best Time to Buy and Sell Stock III": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii "Best Time to Buy and Sell Stock IV": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv "Best Time to Buy and Sell Stock with Cooldown": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown "Best Time to Buy and Sell Stock with Transaction Fee": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee
122. Best Time to Buy and Sell Stock II
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Dynamic Programming": https://leetcode.com/tag/dynamic-programming Similar Questions: "Best Time to Buy and Sell Stock": https://leetcode.com/problems/best-time-to-buy-and-sell-stock "Best Time to Buy and Sell Stock II": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii "Best Time to Buy and Sell Stock IV": https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv "Maximum Sum of 3 Non-Overlapping Subarrays": https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays
123. Best Time to Buy and Sell Stock III
Difficulty: Hard Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Path Sum": https://leetcode.com/problems/path-sum "Sum Root to Leaf Numbers": https://leetcode.com/problems/sum-root-to-leaf-numbers "Path Sum IV": https://leetcode.com/problems/path-sum-iv "Longest Univalue Path": https://leetcode.com/problems/longest-univalue-path
124. Binary Tree Maximum Path Sum
Difficulty: Easy Related Topics: "Two Pointers": https://leetcode.com/tag/two-pointers "String": https://leetcode.com/tag/string Similar Questions: "Palindrome Linked List": https://leetcode.com/problems/palindrome-linked-list "Valid Palindrome II": https://leetcode.com/problems/valid-palindrome-ii
125. Valid Palindrome
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "String": https://leetcode.com/tag/string "Backtracking": https://leetcode.com/tag/backtracking "Breadth-first Search": https://leetcode.com/tag/breadth-first-search Similar Questions: "Word Ladder": https://leetcode.com/problems/word-ladder
126. Word Ladder II
Difficulty: Medium Related Topics: "Breadth-first Search": https://leetcode.com/tag/breadth-first-search Similar Questions: "Word Ladder II": https://leetcode.com/problems/word-ladder-ii "Minimum Genetic Mutation": https://leetcode.com/problems/minimum-genetic-mutation
127. Word Ladder
Difficulty: Hard Related Topics: "Array": https://leetcode.com/tag/array "Union Find": https://leetcode.com/tag/union-find Similar Questions: "Binary Tree Longest Consecutive Sequence": https://leetcode.com/problems/binary-tree-longest-consecutive-sequence
128. Longest Consecutive Sequence
Difficulty: Medium Related Topics: "Tree": https://leetcode.com/tag/tree "Depth-first Search": https://leetcode.com/tag/depth-first-search Similar Questions: "Path Sum": https://leetcode.com/problems/path-sum "Binary Tree Maximum Path Sum": https://leetcode.com/problems/binary-tree-maximum-path-sum
129. Sum Root to Leaf Numbers
Difficulty: Medium Related Topics: "Depth-first Search": https://leetcode.com/tag/depth-first-search "Breadth-first Search": https://leetcode.com/tag/breadth-first-search "Union Find": https://leetcode.com/tag/union-find Similar Questions: "Number of Islands": https://leetcode.com/problems/number-of-islands "Walls and Gates": https://leetcode.com/problems/walls-and-gates
130. Surrounded Regions
Difficulty: Medium Related Topics: "Depth-first Search": https://leetcode.com/tag/depth-first-search "Breadth-first Search": https://leetcode.com/tag/breadth-first-search "Graph": https://leetcode.com/tag/graph Similar Questions: "Copy List with Random Pointer": https://leetcode.com/problems/copy-list-with-random-pointer
133. Clone Graph
Balanced Binary Tree - LeetCode